XML簡介
-
XML是半結(jié)構(gòu)化的數(shù)據(jù)形式,在序列化程序數(shù)據(jù)用以在網(wǎng)絡(luò)中進(jìn)行傳輸?shù)倪^程中非常有用。不是直接將程序中的結(jié)構(gòu)化數(shù)據(jù)變?yōu)槎M(jìn)制數(shù)據(jù),而是在結(jié)構(gòu)化數(shù)據(jù)和半結(jié)構(gòu)化數(shù)據(jù)的XML形式之間進(jìn)行轉(zhuǎn)化。然后使用預(yù)先定義的庫在半結(jié)構(gòu)化數(shù)據(jù)和二進(jìn)制數(shù)據(jù)之間進(jìn)行轉(zhuǎn)換。
-
-
XML中的標(biāo)簽是嵌套的,是棧的形式。
-
- 在
Scala中可以直接以字面量的形式寫XML文件。
- 在
-
Scala中關(guān)于XML的主要類有Elem,Node:所有XML節(jié)點(diǎn)類的抽象父類;Text:僅僅含有文字的節(jié)點(diǎn);NodeSeq:處理節(jié)點(diǎn)的序列,在某些地方可能需要使用處理節(jié)點(diǎn)序列的方法來處理單個節(jié)點(diǎn),這是可以的,Node繼承自NodeSeq。
-
- 在
XML字面量中,可以使用{}進(jìn)行轉(zhuǎn)義來求解Scala代碼的值。在{}不僅可以使用Scala code,也可以使用XML字面量來完成Node的嵌套。xml.NodeSeq.Empty表示為空,nothing,什么都沒有的XML節(jié)點(diǎn)。在{}的<>以及&字符都會被轉(zhuǎn)義。
- 在
scala> <a> {"</a>potential security hole<a>"} </a> res5: scala.xml.Elem = <a> </a>potential security hole<a> </a>
- 不要使用
String append的方式來構(gòu)建XML,例如
- 不要使用
scala> "<a>" + "</a>potential security hole<a>" + "</a>" res5: String = <a></a>potential security hole<a></a>
- 程序員允許了用戶在String中引入
</a>和<a>來改變XML的結(jié)構(gòu),因此是不推薦使用添加字符串的形式來進(jìn)行XML的擴(kuò)建。
- 程序員允許了用戶在String中引入
序列化
- 從程序中的結(jié)構(gòu)化數(shù)據(jù)到
XML的序列化,只需要使用XML字面量和{}進(jìn)行轉(zhuǎn)義計算表達(dá)式的值。如果需要在{}中包含{},則輸入兩個{}即可。
def toXML = <cctherm> <description>{description}</description> <yearMade>{yearMade}</yearMade> <dateObtained>{dateObtained}</dateObtained> <bookPrice>{bookPrice}</bookPrice> <purchasePrice>{purchasePrice}</purchasePrice> <condition>{condition}</condition> </cctherm>
scala> <a> {{{{brace yourself!}}}} </a> res7: scala.xml.Elem = <a> {{brace yourself!}} </a>
反序列化
- Scala中使用
XPath類似的語法來提取XML中的各個部分。
提取tag之間的文字
elem.text
scala> <a> input ---> output </a>.text res9: String = " input ---> output "
提取子元素
使用\方法,使用\\方法可以進(jìn)行遞歸的子元素搜索。
scala> <a><b><c>hello</c></b></a> \"a" res13: scala.xml.NodeSeq = NodeSeq() scala> <a><b><c>hello</c></b></a> \\"a" res14: scala.xml.NodeSeq = NodeSeq(<a><b><c>hello</c></b></a>) //是可以包含自身
提取屬性
使用\方法和\\方法,加入@符號
scala> val joe = <employee name="Joe" rank="code monkey" serial="123"/> scala> joe \"@name" res17: scala.xml.NodeSeq = Joe
反序列化
從上面的提取每個部分元素的方法對XML進(jìn)行反序列化生成結(jié)構(gòu)化的數(shù)據(jù)。
XML和字節(jié)流之間的轉(zhuǎn)換
- 最后一個轉(zhuǎn)換:
XML數(shù)據(jù)和字節(jié)流之間的轉(zhuǎn)換。
- 最后一個轉(zhuǎn)換:
- 最好使用庫來進(jìn)行
XML的轉(zhuǎn)換,可以確定字符編碼,否則需要自己追蹤字符的編碼。
- 最好使用庫來進(jìn)行
將XML轉(zhuǎn)換為字節(jié)數(shù)據(jù):
scala.xml.XML.save("therm1.xml", node)
從字節(jié)數(shù)據(jù)中獲取數(shù)據(jù)生成XML:
val loadnode = xml.XML.loadFile("therm1.xml") loadnode: scala.xml.Elem = ……
- 這些都是基礎(chǔ)的方法,還有許多針對不同讀寫流和輸入輸出流來序列化和反序列化
XML的方法。
模式匹配
- 對
XML使用模式匹配:模式看起來就像是XML字面量。最主要的區(qū)別是在{}中插入的代碼不是一個表達(dá)式而是一個模式。
匹配單個節(jié)點(diǎn)
def proc(node: scala.xml.Node): String = node match { case <a>{contents}</a> => "It's an a: " + contents //這里的<a>與content之間的空格或者換行在node中有需要有強(qiáng)制性的匹配 case <b>{contents}</b> => "It's a b: " + contents case _ => "It's something else." } 可以匹配的XML為<a>It's a comment</a>,不能匹配的為<a><em>It's a comment</em></a>
匹配一個節(jié)點(diǎn)序列,而不是單個節(jié)點(diǎn)
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." }
多次使用模式匹配,跳過空白字符
- 使用變量綁定,將
_*中的內(nèi)容綁定到contents上。模式匹配可以用來跳過XML中的空白字符。
val catalog = <catalog> //空白字符 </cctherm> …… </cctherm> <cctherm> …… </cctherm> </catalog> // catalog中共有5個子節(jié)點(diǎn),有3個空白字符節(jié)點(diǎn),兩個cctherm節(jié)點(diǎn)
// 沒有處理<catalog></catalog>前后的空白字符 catalog match { case <catalog>{therms @ _*}</catalog> => for (therm <- therms) println("processing: " + (therm \"description").text) } //進(jìn)一步使用模式匹配<cctherm>{_*}</cctherm生成for循環(huán)的迭代器。處理了空白字符 catalog match { case <catalog>{therms @ _*}</catalog> => for (therm @ <cctherm>{_*}</cctherm> <- therms) println("processing: " + (therm \"description").text) }