Chapter 28《Working with XML》

半结构化数据

  • XML是一种半结构化数据,既不是纯文本数据也不是编程中使用到的数据结构。在保存数据到文件中或对文件进行网络传输的时候非常有用,将数据转换为半结构数据,然后使用库中的工具将半结构数据转换为二进制数据。

XML简介

  • XML的组成元素为TagTextTag之间是不能交叉的,可以嵌套。Tag可以有自己的属性,属性就是一个name-value对,nameplain的,value值被“”或者‘’包裹起来。

XML字面量

  • Scala支持XML字面量,XML字面量是一个表达式,可用在任意表达式可使用的地方,类型是Scala.xml.Elem,是一个XML元素,其余的重要的类有:Node,是XML所有节点类的抽象总类;Text,只包含有文本的Node
  • NodeSeq类含有Node序列,许多XML的库都支持对NodeSeq的操作,Node继承自NodeSeq
    构造XML字面量的时候可以在其中嵌入Scala表达式,使用{}包括起来。如果在表达式中插入Tag,直接写入即可。直接写入标签,空节点使用XML.NodeSeq.Empty表达。
    scala>  {if (yearMade < 2000) {yearMade} else xml.NodeSeq.Empty} 
    
    scala>  {"potential security hole"} 
    res4: scala.xml.Elem =  </a>potential security
    hole<a> 
    

其中<,>$会被转义成为对应的字符实体。如果使用单纯的字符串拼接,则无法阻止用户对XML的修改,会造成错误的情况发生。

scala> "" + "potential security hole" + ""
res5: String = potential security hole

所以最好还是使用XML字面量来生成XML Elem

序列化

  • 第一种序列化:在内部的数据结构中定义一个toXML方法,使用XML字面量手动构建XML

拆分XML

  • 方法基于XPath语言,可以直接在Scala中使用。使用text方法可以直接提取到XML节点之间的文字,其中的<,>$可以被自动的转换。
    使用\可以提取XML中的子节点。
    使用\\可以提取任意深度的子节点。
    scala> hello \\"c"
    res12: scala.xml.NodeSeq = NodeSeq(hello)
    

同样可以使用这两个方法来提取属性

scala> val joe = 
joe: scala.xml.Elem = 
scala> joe \\ "@name"
res15: scala.xml.NodeSeq = Joe

"@name"是在被提取的字符串里面的。

反序列化

  • 通过\\可以对一个类定义parser来解析相应的XML,将其反序列化为相应的数据结构。

加载和保存

  • 序列化的最后一步是XML和字节之间的转换,这部分一般都有相应的库函数来做。将XML转为String,调用toString即可,但还是推荐使用scala.xml.XML.save("therm1.xml", node)函数将XML转为文件进行保存,同时可以指定文件的编码。导入更简单,使用 val loadnode = xml.XML.loadFile("therm1.xml")

XML中的模式匹配

  • 以上的例子都是在非常确定XML结构的情况下做的序列化和反序列化,如果一个XML的结构是不确定的,则使用模式匹配来筛选可能性。用于匹配的模式非常像XML字面量,在其中也可以嵌入使用{}包裹的表达式,但{}`中的表达式不再计算,而是一个可以被使用的模式,
    def proc(node: scala.xml.Node): String =
    node match {
    case {contents} => "It's an a: " + contents
    case {contents} => "It's a b: " + contents
    case _ => "It's something else."
    }
    

其中ab只能匹配只有一个节点的XML,例如apple此类可以,标签中间只能有一个节点,不能有多的节点。scala这样是不行的。如果要使提取出来这种XML序列,使用_*进行匹配,可以使用变量绑定,将_*的值赋值到contents上方便以后使用。

def proc(node: scala.xml.Node): String =
node match {
case {contents @ _*} => "It's an a: " + contents
case {contents @ _*} => "It's a b: " + contents
case _ => "It's something else."
}

XML中,换行或者空格等空白字符也都是一个节点,

你可能感兴趣的:(Chapter 28《Working with XML》)