Đâ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 open
và close
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>)