Chapter 28《Working with XML》

作者: liqing151 | 来源:发表于2018-08-20 19:52 被阅读0次

    半结构化数据

    • 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,直接写入即可。直接写入<old></old>标签,空节点使用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> &lt;/a&gt;potential security
      hole&lt;a&gt; </a>
      

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

    scala> "<a>" + "</a>potential security hole<a>" + "</a>"
    res5: String = <a></a>potential security hole<a></a>
    

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

    序列化

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

    拆分XML

    • 方法基于XPath语言,可以直接在Scala中使用。使用text方法可以直接提取到XML节点之间的文字,其中的<,>$可以被自动的转换。
      使用\可以提取XML中的子节点。
      使用\\可以提取任意深度的子节点。
      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,将其反序列化为相应的数据结构。

    加载和保存

    • 序列化的最后一步是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 <a>{contents}</a> => "It's an a: " + contents
      case <b>{contents}</b> => "It's a b: " + contents
      case _ => "It's something else."
      }
      

    其中ab只能匹配只有一个节点的XML,例如<a>apple</a><b><c/></b>此类可以,标签中间只能有一个节点,不能有多的节点。<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中,换行或者空格等空白字符也都是一个节点,

    相关文章

      网友评论

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

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