這是另一種值得考慮的方法。我們本質上是要從一個字符串構建scala.xml.Elem並利用一些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)
}
首先,我們創建了open
和close
標籤,這僅僅是字符串。然後我們通過使用一些XPath風格的查詢構造children
。
\\
是Elem上的一個運算符,它返回Elem的元素和所有子序列。
\
是相似的,但它返回元素的元素。
"_"
是通配符。
爲什麼不只是\
?我根據文檔自己找出了問題,但是查看XPath for Java讓我相信\\
包含整個Elem本身和兒童,而\
只包含孩子,所以如果我們有<parent><x/></parent> \ "parent"
,我們將找不到任何東西,因爲只有<x/>
是通過。
現在這種方法並不可怕。我們可以做些什麼來讓它變得更棒?我們最好使用Scala的精彩Option
類和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))
}
}
當然這具有工作只是一個ELEM,情況父不存在的甜蜜額外的好處,並作爲參數提供ELEM可變數量。下面是一個很長的例子,我用這個最後的方法運行,
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>)