Scala XML解析库
来源:互联网 发布:公安网络安全保密协议 编辑:程序博客网 时间:2024/05/22 11:52
XML 解析
Scala标准库中内置了XML支持,XML相关类在包scala.xml
中。
XML节点类型
Node
是最基础的XML节点类型(抽象类)。 Node
类型是NodeSeq
的子类,而NodeSeq
继承自Seq[Node]
,用于记录节点的序列。 Node
类型定义了一系列用于获取节点信息的方法:
prefix
成员方法,用于获取当前节点的标签前缀。child
成员方法(抽象方法),用于获取子节点的序列。attributes
成员方法,用于获取当前节点的属性。label
成员方法(抽象方法),用于获取当前节点的标签名称。text
成员方法,用于获取当前节点的文本内容。
如下所示:
def prefix: String = nulldef child: Seq[Node]def attributes: MetaData = Nulldef label: Stringoverride def text: String = super.text
Node
类型的伴生对象中定义了提取器,可以用于提取节点中的标签名称、属性、子节点等内容:
def unapplySeq(n: Node) = Some((n.label, n.attributes, n.child))
Elem
类型继承于Node
类型,实现了Node
类型中的抽象内容。
有如下测试XML文件:
<!-- FileName: Example.xml --><root> <node arg="arg_node"> <node1 arg="arg_node1">node1</node1> <node1 argOne="node1_arg_one" argTwo="node1_arg_two">test_node1</node1> </node> <node><node2>node2</node2></node> <node> <node3 arg="arg_node3">node3</node3> <node4 arg="arg_node4">node4</node4> </node></root>
加载与保存XML文件
加载和保存XML文件可以使用XMLLoader
特质以及继承于XMLLoader[Elem]
的单例对象XML
。
XMLLoader
的实例方法loadFile()
可以从指定路径加载XML文件进行解析,方法返回由输入XML文件生成的Elem
节点对象。XML
对象的方法save()
和write()
可用于XML节点(Node
类型)保存到文件中。save()
方法接收文件路径(String
类型)作为参数,大部分参数带有默认值。write()
接收java.io.Writer
类型作为参数,参数没有默认值。
查找节点和节点属性
NodeSeq
类提供了\()
、\\()
等方法用于节点的查找,继承于NodeSeq
类的Node
、Elem
等类型都可以使用这些方法进行节点查找。
查找节点
\()
以及\\()
方法签名类似,接收节点名称作为参数(String
类型),返回节点序列(NodeSeq
类型)。
\()
方法返回当前节点下一级子节点中指定名称节点的序列。\\()
方法返回当前节点所有子节点中指定名称节点的序列。- 使用
loadFile()
方法加载XML文件后,返回的Elem
类型的当前节点为根节点。 - 节点查找支持使用模式匹配的方式。
- 使用模式匹配方式查找节点时,匹配表达式中的节点标签不能带有属性(不支持)。
节点属性
节点属性内容可以直接从节点中获取,也可以通过查找获取属性内容。
- 使用
\()
、\\()
方法同样可以进行属性查找,需要在属性名字符串前加上@
字符表示搜索的内容为属性,如\("@num")
表示查找名称为num
的属性内容。 - 在使用
\()
方法查找属性时,查找的的范围不是子节点的属性,而是当前节点的属性。 - 可以直接使用
\@()
方法在当前子节点中进行属性查找,直接使用属性名作为参数,无需再添加@
字符。 - 还可以使用
attribute()
以及attributes()
方法从节点中获取属性。
遍历节点
Elem
类型的成员字段child
保存了子节点的序列(Seq[Node]
类型),可以通过for
循环语句进行遍历:
import scala.xml._object Main extends App { val xmlFile = XML.loadFile("Example.xml") val getChild: Node => Unit = rootNode => for (node <- rootNode.child) node match { //如果只需要节点文本,可以将表达式嵌在匹配语句中 case <node1>{ text }</node1> => println("Node1 text: " + text) //支持多级标签匹配 case <node><node2>{ text }</node2></node> => println("Case node_node2: " + text) //如果需要整个节点的内容,需要使用@符号 case n @ <node2>{ _ }</node2> => println("Node2 text: " + n.text) //使用attribute()或者attributes()方法获取节点的属性 case n @ <node3>{ _ }</node3> => println("Node3 attribute: " + n.attribute("arg").get) case n @ <node4>{ _ }</node4> => println("Node4 attribute: " + n.attributes("arg")) //匹配其它类型节点,也可以写成 case _ if node.child.length > 0 => ... case _ if node.child != null => getChild(node) } getChild(xmlFile)}
遍历节点同样可以使用高阶函数,以上代码等价于:
import scala.xml._object Main extends App { val xmlFile = XML.loadFile("Example.xml") val getChild: Node => Unit = rootNode => rootNode.child foreach { node => node match { case <node1>{ text }</node1> => println("Node1 text: " + text) case <node><node2>{ text }</node2></node> => println("Case node_node2: " + text) case n @ <node2>{ _ }</node2> => println("Node2 text: " + n.text) //若仅需要属性的内容,可以直接在模式匹配表达式中获取属性(n为Node类型) case <node3>{ n @ _ }</node3> => println("Node3 attribute: " + n.text) //若需要从模式匹配表达式中获取多个属性,则可以写成(n为Seq[Node]类型) case <node4>{ n @ _* }</node4> => println("Node4 attribute: " + n(0).text) //匹配其它类型节点,也可以写成 case _ if node.child.length > 0 => ... case _ if node.child != null => getChild(node) } } getChild(xmlFile)}
输出结果:
Node1 text: node1
Node1 text: test_node1
Case node_node2: node2
Node3 attribute: arg_node3
Node4 attribute: arg_node4
创建XML
可以直接将代码嵌入XML语句中:
scala> val str = "Test"str: String = Testscala> val node0 = <li>{ str }</li> //xml节点内容可以插入变量,使用花括号区分表达式与xml本身内容node0: scala.xml.Elem = <li>Test</li>scala> val node1 = <li name={ str }>test</li> //xml属性中插入变量node1: scala.xml.Elem = <li name="Test">test</li>
可以将复杂的表达式在XML语句中进行多重嵌套:
scala> val node3 = <ul>{ for (i <- 1 to 3) yield <li>{ i }</li> }</ul>node3: scala.xml.Elem = <ul><li>1</li><li>2</li><li>3</li></ul>
在Scala中,节点是不可变的,拼接节点的正确方式是使用Elem
类型的cospy()
方法,并在复制时重新设定child
参数。 copy()
方法的定义如下所示:
def copy( prefix: String = this.prefix, label: String = this.label, attributes: MetaData = this.attributes, scope: NamespaceBinding = this.scope, minimizeEmpty: Boolean = this.minimizeEmpty, child: Seq[Node] = this.child.toSeq): Elem = Elem(prefix, label, attributes, scope, minimizeEmpty, child: _*)
使用copy()
方法拼接节点如下所示:
//使用具名参数指定子节点内容scala> node3.copy(child = node0 ++ node1)res0: scala.xml.Elem = <ul><li>Test</li><li name="Test">test</li></ul>//保留原节点的内容进行拼接scala> node3.copy(child = node3.child ++ node0 ++ node1)res1: scala.xml.Elem = <ul><li>1</li><li>2</li><li>3</li><li>Test</li><li name="Test">test</li></ul>//创建新节点时也可以设定其它属性,如标签名、标签前缀等scala> node3.copy(child = node0 ++ node1, prefix = "Test", label = "test")res2: scala.xml.Elem = <Test:test><li>Test</li><li name="Test">test</li></Test:test>
- Scala XML解析库
- scala解析xml
- Scala解析XML
- scala解析xml
- scala xml
- scala 解析
- xml 解析库
- 一个XML解析库
- XML解析库比较
- XML解析库
- XML解析库
- XML解析库RapidXML
- EXPAT(XML解析库)
- XML解析库比较
- XML解析库
- TinyXML 库解析XML
- XML解析生成库
- GDataXMLNode库 XML解析
- 布线问题
- 自定义PopupWindow
- phpcms v9网站搬家的方法(含域名更改)
- 【Ionic】ionic安装和项目的创建
- linux分区方案
- Scala XML解析库
- hitTest、pointInside实例
- Google浏览器开发者工具:CSSViewer(一个Css查看器)
- HDU 1828 线段树之扫描线之周长并
- IOS 正则表达式
- android 广播接收器之通知栏页面跳转
- 你真的了解iOS代理设计模式吗?
- 增值税等普通发票扫描识别系统
- 主从同步设置的重要参数log_slave_updates