Chapter 28 《Working with XML》

作者: liqing151 | 来源:发表于2018-06-11 15:04 被阅读1次

XML简介

    1. XML是半结构化的数据形式,在序列化程序数据用以在网络中进行传输的过程中非常有用。不是直接将程序中的结构化数据变为二进制数据,而是在结构化数据和半结构化数据的XML形式之间进行转化。然后使用预先定义的库在半结构化数据和二进制数据之间进行转换。
    1. XML中的标签是嵌套的,是栈的形式。
    1. Scala中可以直接以字面量的形式写XML文件。
    1. Scala中关于XML的主要类有ElemNode:所有XML节点类的抽象父类;Text:仅仅含有文字的节点;NodeSeq:处理节点的序列,在某些地方可能需要使用处理节点序列的方法来处理单个节点,这是可以的,Node继承自NodeSeq
    1. XML字面量中,可以使用{}进行转义来求解Scala代码的值。在{}不仅可以使用Scala code,也可以使用XML字面量来完成Node的嵌套。 xml.NodeSeq.Empty表示为空,nothing,什么都没有的XML节点。在{}<>以及&字符都会被转义。
scala>  <a> {"</a>potential security hole<a>"} </a>
res5: scala.xml.Elem = <a> &lt;/a&gt;potential security hole&lt;a&gt; </a>
    1. 不要使用String append的方式来构建XML,例如
scala> "<a>" + "</a>potential security hole<a>" + "</a>"
res5: String = <a></a>potential security hole<a></a>
    1. 程序员允许了用户在String中引入</a><a>来改变XML的结构,因此是不推荐使用添加字符串的形式来进行XML的扩建。

序列化

  • 从程序中的结构化数据到XML的序列化,只需要使用XML字面量和{}进行转义计算表达式的值。如果需要在{}中包含{},则输入两个{}即可。
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 ---&gt; output </a>.text
res9: String = " input ---> output "
提取子元素

使用\方法,使用\\方法可以进行递归的子元素搜索。

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进行反序列化生成结构化的数据。


XML和字节流之间的转换

    1. 最后一个转换:XML数据和字节流之间的转换。
    1. 最好使用库来进行XML的转换,可以确定字符编码,否则需要自己追踪字符的编码。
将XML转换为字节数据:
scala.xml.XML.save("therm1.xml", node)
从字节数据中获取数据生成XML
val loadnode = xml.XML.loadFile("therm1.xml") loadnode: scala.xml.Elem = ……
  • 这些都是基础的方法,还有许多针对不同读写流和输入输出流来序列化和反序列化XML的方法。

模式匹配

  • XML使用模式匹配:模式看起来就像是XML字面量。最主要的区别是在{}中插入的代码不是一个表达式而是一个模式。
匹配单个节点
def proc(node: scala.xml.Node): String = node match {
case <a>{contents}</a> => "It's an a: " + contents //这里的<a>与content之间的空格或者换行在node中有需要有强制性的匹配
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>
匹配一个节点序列,而不是单个节点
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."
}
多次使用模式匹配,跳过空白字符
  • 使用变量绑定,将_*中的内容绑定到contents上。模式匹配可以用来跳过XML中的空白字符。
val catalog =
  <catalog> //空白字符
    </cctherm>
       ……
    </cctherm>
    <cctherm>
        ……
   </cctherm>
 </catalog> // catalog中共有5个子节点,有3个空白字符节点,两个cctherm节点
// 没有处理<catalog></catalog>前后的空白字符
catalog match {
    case <catalog>{therms @ _*}</catalog> =>
        for (therm <- therms)
            println("processing: " +
                    (therm \"description").text)
}
//进一步使用模式匹配<cctherm>{_*}</cctherm生成for循环的迭代器。处理了空白字符
catalog match {
    case <catalog>{therms @ _*}</catalog> =>
        for (therm @ <cctherm>{_*}</cctherm> <-
                     therms)
            println("processing: " +
                    (therm \"description").text)
}

相关文章

网友评论

    本文标题:Chapter 28 《Working with XML》

    本文链接:https://www.haomeiwen.com/subject/hcpceftx.html