半结构化数据
-
XML
是一种半结构化数据,既不是纯文本数据也不是编程中使用到的数据结构。在保存数据到文件中或对文件进行网络传输的时候非常有用,将数据转换为半结构数据,然后使用库中的工具将半结构数据转换为二进制数据。
XML简介
-
XML
的组成元素为Tag
和Text
,Tag
之间是不能交叉的,可以嵌套。Tag
可以有自己的属性,属性就是一个name-value
对,name
是plain
的,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> </a>potential security hole<a> </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." }
其中a
和b
只能匹配只有一个节点的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
中,换行或者空格等空白字符也都是一个节点,
网友评论