半結(jié)構(gòu)化數(shù)據(jù)
-
XML
是一種半結(jié)構(gòu)化數(shù)據(jù),既不是純文本數(shù)據(jù)也不是編程中使用到的數(shù)據(jù)結(jié)構(gòu)赁严。在保存數(shù)據(jù)到文件中或?qū)ξ募M行網(wǎng)絡傳輸?shù)臅r候非常有用,將數(shù)據(jù)轉(zhuǎn)換為半結(jié)構(gòu)數(shù)據(jù)员帮,然后使用庫中的工具將半結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)換為二進制數(shù)據(jù)榜轿。
XML簡介
-
XML
的組成元素為Tag
和Text
幽歼,Tag
之間是不能交叉的,可以嵌套谬盐。Tag
可以有自己的屬性甸私,屬性就是一個name-value
對,name
是plain
的飞傀,value
值被“”
或者‘’
包裹起來皇型。
XML字面量
-
Scala
支持XML
字面量砸烦,XML
字面量是一個表達式弃鸦,可用在任意表達式可使用的地方,類型是Scala.xml.Elem
幢痘,是一個XML
元素唬格,其余的重要的類有:Node
,是XML
所有節(jié)點類的抽象總類颜说;Text
购岗,只包含有文本的Node
, -
NodeSeq
類含有Node
序列门粪,許多XML
的庫都支持對NodeSeq
的操作喊积,Node
繼承自NodeSeq
。
構(gòu)造XML
字面量的時候可以在其中嵌入Scala
表達式玄妈,使用{}
包括起來注服。如果在表達式中插入Tag
,直接寫入即可措近。直接寫入<old></old>
標簽溶弟,空節(jié)點使用XML.NodeSeq.Empty
表達。scala> <a> {if (yearMade < 2000) <old>{yearMade}</old> else xml.NodeSeq.Empty} </a> scala> <a> {"</a>potential security hole<a>"} </a> res4: scala.xml.Elem = <a> </a>potential security hole<a> </a>
其中<,>
和$
會被轉(zhuǎn)義成為對應的字符實體瞭郑。如果使用單純的字符串拼接辜御,則無法阻止用戶對XML
的修改,會造成錯誤的情況發(fā)生屈张。
scala> "<a>" + "</a>potential security hole<a>" + "</a>" res5: String = <a></a>potential security hole<a></a>
所以最好還是使用XML
字面量來生成XML Elem
擒权。
序列化
- 第一種序列化:在內(nèi)部的數(shù)據(jù)結(jié)構(gòu)中定義一個
toXML
方法,使用XML
字面量手動構(gòu)建XML
阁谆。
拆分XML
- 方法基于
XPath
語言碳抄,可以直接在Scala
中使用。使用text
方法可以直接提取到XML
節(jié)點之間的文字场绿,其中的<,>
和$
可以被自動的轉(zhuǎn)換剖效。
使用\
可以提取XML
中的子節(jié)點。
使用\\
可以提取任意深度的子節(jié)點。scala> <a><b><c>hello</c></b></a> \\"c" res12: scala.xml.NodeSeq = NodeSeq(<c>hello</c>)
同樣可以使用這兩個方法來提取屬性
scala> val joe = <employee name="Joe" rank="code monkey" serial="123"/> joe: scala.xml.Elem = <employee name="Joe" rank="code monkey" serial="123"/> scala> joe \\ "@name" res15: scala.xml.NodeSeq = Joe
"@name"
璧尸,@
是在被提取的字符串里面的咒林。
反序列化
- 通過
\\
可以對一個類定義parser
來解析相應的XML
,將其反序列化為相應的數(shù)據(jù)結(jié)構(gòu)爷光。
加載和保存
- 序列化的最后一步是
XML
和字節(jié)之間的轉(zhuǎn)換垫竞,這部分一般都有相應的庫函數(shù)來做。將XML
轉(zhuǎn)為String
蛀序,調(diào)用toString
即可欢瞪,但還是推薦使用scala.xml.XML.save("therm1.xml", node)
函數(shù)將XML轉(zhuǎn)為文件進行保存,同時可以指定文件的編碼徐裸。導入更簡單引有,使用val loadnode = xml.XML.loadFile("therm1.xml")
XML中的模式匹配
- 以上的例子都是在非常確定
XML結(jié)構(gòu)的情況下做的序列化和反序列化,如果一個
XML的結(jié)構(gòu)是不確定的倦逐,則使用模式匹配來篩選可能性。用于匹配的模式非常像
XML字面量宫补,在其中也可以嵌入使用
{}包裹的表達式檬姥,但
{}`中的表達式不再計算,而是一個可以被使用的模式粉怕,def proc(node: scala.xml.Node): String = node match { case <a>{contents}</a> => "It's an a: " + contents case <b>{contents}</b> => "It's a b: " + contents case _ => "It's something else." }
其中a
和b
只能匹配只有一個節(jié)點的XML
健民,例如<a>apple</a>
,<b><c/></b>
此類可以贫贝,標簽中間只能有一個節(jié)點秉犹,不能有多的節(jié)點。<a>scala<b/></a>
這樣是不行的稚晚。如果要使提取出來這種XML
序列崇堵,使用_*
進行匹配,可以使用變量綁定客燕,將_*
的值賦值到contents
上方便以后使用鸳劳。
def proc(node: scala.xml.Node): String = node match { case <a>{contents @ _*}</a> => "It's an a: " + contents case <b>{contents @ _*}</b> => "It's a b: " + contents case _ => "It's something else." }
在XML
中,換行或者空格等空白字符也都是一個節(jié)點也搓,