2011-10-16 27 views
5

Tôi tò mò về cách tốt nhất để kết hợp một tập hợp các cây xml chứa dữ liệu tương tự thành một tập hợp đơn (kiểu 'công đoàn').Scala: Kết hợp các cây dữ liệu xml?

Tôi đã thực hiện một giải pháp làm việc nhưng mã trông xấu và tôi có cảm giác ruột mạnh mẽ rằng phải có một cách đẹp hơn và nhỏ gọn hơn thực hiện việc này.

Những gì tôi đang cố gắng làm là trong trường hợp đơn giản kết hợp một cái gì đó như:

<fruit> <apple /> <orange /> </fruit> 

và:

<fruit> <banana /> </fruit> 

Để:

<fruit> <apple/> <orange/> <banana/> </fruit> 

Bất kỳ ý tưởng hay làm thế nào để thực hiện một cách sạch sẽ điều này trong scala?

Trả lời

1

với

val appleAndOrange : Elem = <fruit> <apple/> <orange/> </fruit> 

val banana : Elem = <fruit> <banana> </fruit> 

bạn có thể làm

val all = appleAndOrange.copy(child = appleAndOrange.child ++ banana.child) 

Tuy nhiên, điều này chỉ đơn giản là lấy nhãn <fruit> từ appleAndOrange, và bỏ qua một từ banana, mà ở đây xảy ra giống nhau. Tương tự cho Bạn phải quyết định những gì bạn muốn kiểm tra và hành vi gì, nếu họ không giống nhau. Tương tự cho tiền tố, thuộc tính và phạm vi.

1

Đây là một cách tiếp cận khác đáng xem xét. Về cơ bản, chúng tôi sẽ xây dựng tệp scala.xml.Elem từ một chuỗi và sử dụng một số truy vấn kiểu XPath.

import scala.xml._ 
def childUnion(parent: String, a: Elem, b: Elem): Elem = { 
    val open:String = "<" + parent + ">" 
    val close:String = "</" + parent + ">" 
    val children = a \\ parent \ "_" ++ b \\ parent \ "_" 
    return XML.loadString(open + children + close) 
} 

Đầu tiên chúng tôi tạo ra openclose thẻ, mà chỉ là chuỗi. Sau đó, chúng tôi xây dựng children bằng cách sử dụng một số truy vấn kiểu XPath.

\\ là nhà điều hành trên Elem, trả về các phần tử và tất cả các dãy của Elem.

\ tương tự nhưng nó trả về các phần tử của Elem.

"_" là ký tự đại diện.

Tại sao không chỉ \? Tôi đã gặp khó khăn trong việc tìm ra điều này dựa trên tài liệu hướng dẫn nhưng nhìn XPath cho Java dẫn tôi tin rằng \\ bao gồm toàn bộ Elem và trẻ em trong khi \ chỉ bao gồm các trẻ em, vì vậy nếu chúng tôi có <parent><x/></parent> \ "parent" chúng tôi sẽ không tìm thấy gì vì chỉ <x/> là thông qua.

Phương pháp này không tuyệt vời. Chúng ta có thể làm gì để làm cho nó tuyệt vời hơn một chút? Chúng tôi muốn sử dụng tốt hơn lớp học tuyệt vời của Scala Option và phương pháp foldLeft.

def childUnion(parent: String, a: Elem, b: Elem*): Option[Elem] = { 
    val parentElem = a \\ parent 

    parentElem.size match { 
     case 0 => None // no parent present 
     case _ => 
      val children = b.foldLeft(parentElem \ "_")((d,c) => (d ++ (c \\ parent \ "_"))) 
      val open:String = "<" + parent + ">" 
      val close:String = "</" + parent + ">" 
      Some(XML.loadString(open + children + close)) 
    } 
} 

Điều này tất nhiên có lợi ích bổ sung khi làm việc chỉ với một Elem, trường hợp không có mặt và số Elem được cung cấp làm đối số. Dưới đây là danh sách dài các ví dụ tôi đã chạy khi đưa ra phương pháp cuối cùng này,

scala> a 
res85: scala.xml.Elem = <fruit> <apple></apple> <orange></orange> </fruit> 

scala> b 
res86: scala.xml.Elem = <fruit> <banana></banana> </fruit> 

scala> c 
res87: scala.xml.Elem = <box><fruit><apple></apple></fruit></box> 

scala> d 
res88: scala.xml.Elem = <box><nofruit></nofruit></box> 

scala> e 
res89: scala.xml.Elem = <fruit></fruit> 

scala> val f = <fruit /> 
f: scala.xml.Elem = <fruit></fruit> 

scala> childUnion("fruit", a) 
res91: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>) 

scala> childUnion("fruit", b) 
res92: Option[scala.xml.Elem] = Some(<fruit><banana></banana></fruit>) 

scala> childUnion("fruit", c) 
res93: Option[scala.xml.Elem] = Some(<fruit><apple></apple></fruit>) 

scala> childUnion("fruit", d) 
res94: Option[scala.xml.Elem] = None 

scala> childUnion("fruit", e) 
res95: Option[scala.xml.Elem] = Some(<fruit></fruit>) 

scala> childUnion("fruit", a, b) 
res96: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><banana></banana></fruit>) 

scala> childUnion("fruit", a, e) 
res97: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>) 

scala> childUnion("fruit", a, c) 
res98: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><apple></apple></fruit>) 

scala> childUnion("fruit", a, d) 
res99: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>) 

scala> childUnion("fruit", e, d) 
res100: Option[scala.xml.Elem] = Some(<fruit></fruit>) 

scala> childUnion("fruit", d, d) 
res101: Option[scala.xml.Elem] = None 

scala> childUnion("fruit", f) 
res102: Option[scala.xml.Elem] = Some(<fruit></fruit>) 
Các vấn đề liên quan