第二十七节 Scala操纵XML
2017-01-24 14:48
393 查看
本节主要内容
XML 字面量XML内容提取
XML对象序列化及反序列化
XML文件读取与保存
XML模式匹配
1. XML 字面量
XML是一种非常重要的半结构化数据表示方式,目前大量的应用依赖于XML,这些应用或利用XML作为数据交换格式,或利用XML进行文件配置等。像Java、C++及其它流行的程序开发语言都是依赖于第三方库来实现XML的操作,例如JAVA经常通过JDOM,DOM4J等XML处理工具进行XML的操纵,但Scala提供了对XML的原生支持,通过scala.xml._包下的类或对象可以进行任何的XML操作。下面的代码演示了Scala中如何定义XML字面量。scala> var x: scala.xml.Elem = <site><name>xuetuwuyou</name><url>http://www.xuet uwuyou.com/</url></site> x: scala.xml.Elem = <site><name>xuetuwuyou</name><url>http://www.xuetuwuyou.com/ </url></site> scala> <site><name>xuetuwuyou</name><url>http://www.xuetuwuyou.com/</url></site> res8: scala.xml.Elem = <site><name>xuetuwuyou</name><url>http://www.xuetuwuyou.c om/</url></site>1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
通过上面的代码不能发现,scala会自动地对XML进行解析,并识别为scala.xml.Elem类型。scala中与XML相关的包和类很多,具体如下图所示:
在深入讲解Scala操纵XML之前,先对几个主要的术语进行介绍:
图中描述了属性、根元素、子元素、元素及文本的概念及它们之间的关联关系,所以的文本、元素被统称为节点(Node)。下面给出的scala XML中的几个重要的类:
Node类。它的一个抽象类,用于对象XML中的所有节点进行抽象:
Text类,仅包含文本的节点,例如
<url>http://www.xuetuwuyou.com/</url>中的http://www.xuetuwuyou.com/就是一种Text对象
NodeSeq类,它同样是一个抽象类,指的是节点的序列,Node继承自NodeSeq,可以看Node可作是NodeSeq只有一个元素的情况。
scala中的XML中可以执行scala表达式,例如
val s="http://www.xuetuwuyou.com/" val xmlUrl= <a>{" "+s+" "}</a> //<a> http://www.xuetuwuyou.com/ </a> println(xmlUrl) val age=30 val xml1= if(age<29) <age> {age} </age> else NodeSeq.Empty //<age> 28 </age println(xml1) //<age> 79 </age> val xml2= <age> {29+50} </age> println(xml2)1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
2. XML内容提取
提取XML中的文本:object ExtractXMLText extends App{ val x= <person><name>摇摆少年梦</name><age>27</age></person> //摇摆少年梦27 println(x.text) }1
2
3
4
5
1
2
3
4
5
这种提取方式将XML中所有的文本内容提取出来并拼接在一起,在实际中我们可能需要精确提取,比如我只想提取name元素中的内容,此时可以采用下列方式:
val x= <person><name>摇摆少年梦</name><age>27</age></person> //提取name子结点,类型XPATH访问方式 //<name>摇摆少年梦</name> println(x \ "name") //提取name中的文本 println((x \ "name").text) scala> x \ "age" res2: scala.xml.NodeSeq = NodeSeq(<age>27</age>)1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
x \ “age” 这种子元素的提取方式,返回的类型是scala.xml.NodeSeq
\的方式只能提取子元素,不能提取子元素的子元素,例如:
val x= <persons> <person><name>摇摆少年梦</name><age>27</age></person> <person><name>张三</name><age>29</age></person> <person><name>李四</name><age>30</age></person> </persons> //返回空NodeSeq println(x \ "name") // \\提取二级子元素 //<name>摇摆少年梦</name><name>张三</name><name>李四</name> println(x \\ "name")1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
通过\和\可以提取任何XML的子元素及其文本内容,但如果XML元素带有属性,那又如何提取呢?
val x= <persons> <person name="摇摆少年梦" age="27" /> <person><name>张三</name><age>29</age></person> <person><name>李四</name><age>30</age></person> </persons> //用@方式提取name属性 //摇摆少年梦 println(x \\ "@name")1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
3. XML对象序列化及反序列化
下面给出的是对象的XML序列化操作:class Person(val name:String,val age:Int){ def toXML()={ <person> <name>{name}</name> <age>{age}</age> </person> } } object XMLSerialization extends App{ val p=new Person("摇摆少年梦",27) println(p.toXML()) }1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
反序列化操作:
class Person(val name:String,val age:Int){ //序列化操作 def toXML()={ <person> <name>{name}</name> <age>{age}</age> </person> } //反序列化操作 def fromXML(xml:scala.xml.Elem):Person={ new Person((xml \ "name").text,(xml \ "age").text.toInt) } override def toString()="name="+name+", age="+age } object XMLSerialization extends App{ val p=new Person("摇摆少年梦",27) val xmlPerson=p.toXML() val p2=p.fromXML(xmlPerson) println(p2) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4. XML文件读取与保存
前一小节,我们的序列化与反序列化操作都在内存中进行的,在通常的情况下都是将序列化后的XML保存在文件当中,在反序列化时再从文件中读取,实现方式如下:class Person(val name:String,val age:Int){ def toXML()={ <person> <name>{name}</name> <age>{age}</age> </person> } def fromXML(xml:scala.xml.Elem):Person={ new Person((xml \ "name").text,(xml \ "age").text.toInt) } override def toString()="name="+name+", age="+age } object XMLSerialization extends App{ val p=new Person("摇摆少年梦",27) val xmlPerson=p.toXML() //保存到XML文件当中 scala.xml.XML.save("person.xml", xmlPerson, "UTF-8", true, null) //从文件中加载XML文件 val loadPerson=scala.xml.XML.loadFile("person.xml") val p2=p.fromXML(loadPerson) println(p2) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
下面给出的是save方法的标签
/** Saves a node to a file with given filename using given encoding * optionally with xmldecl and doctype declaration. * * @param filename the filename * @param node the xml node we want to write * @param enc encoding to use * @param xmlDecl if true, write xml declaration * @param doctype if not null, write doctype declaration */ final def save( filename: String, node: Node, enc: String = encoding, xmlDecl: Boolean = false, doctype: dtd.DocType = null ): Unit =1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
5. XML模式匹配
Scala操纵XML另外一个非常强大的地方在于,它能够用于模式匹配,从而非常灵活、方便地对XML进行处理:import scala.xml._ object PatternMatchingXML extends App{ def xmlMatching(node:Node)={ node match { //XML模式匹配语法,利用{}进行匹配 case <persons>{sub_element}</persons>=> println(sub_element) //其它未匹配的情况 case _ => println("no matching") } } //下面这条语句的执行结果:<person><name>摇摆少年梦</name></person> xmlMatching(<persons><person><name>摇摆少年梦</name></person></persons>) //下面这条语句的执行结果: //no matching xmlMatching(<persons><person><name>摇摆少年梦</name></person><person><name>摇摆少年梦</name></person></persons>) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
从上述代码可以看到,
<persons>{sub_element}</persons>只能匹配标签
<persons></persons>中只存在单个子元素的情况,如果具有多个子元素,即子元素构成NodeSeq,则不能匹配,需要进行进一步处理,代码如下:
object PatternMatchingXML extends App{ def xmlMatching(node:Node)={ node match { //_*的方式表示可以匹配多个子元素的情况,如果匹配 //则将匹配的内容赋值给sub_element case <persons>{sub_element @ _*}</persons>=> println(sub_element) case _ => println("no matching") } } //下面这条语句返回的是:ArrayBuffer(<person><name>摇摆少年梦</name></person>) //数组中的每个元素都是Node类型 xmlMatching(<persons><person><name>摇摆少年梦</name></person></persons>) //下面这条语句返回的是:ArrayBuffer(<person><name>摇摆少年梦</name></person>, <person><name>摇摆少年梦</name></person>) //数组中的每个元素都是Node类型 xmlMatching(<persons><person><name>摇摆少年梦</name></person><person><name>摇摆少年梦</name></person></persons>) }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
因为返回的是ArrayBuffer,可以通过for循环遍历对XML子元素中的内容进行提取,如:
def xmlMatching2(node:Node)={ node match { case <persons>{sub_element @ _*}</persons>=> for(elm <- sub_element) println("getting "+(elm \ "name").text) case _ => println("no matching") } } //返回结果getting 摇摆少年梦 xmlMatching2(<persons><person><name>摇摆少年梦</name></person></persons>) //返回结果: //getting 摇摆少年梦 //getting 摇摆少年梦 xmlMatching2(<persons><person><name>摇摆少年梦</name></person><person><name>摇摆少年梦</name></person></persons>)
相关文章推荐
- Windows下Scala环境搭建
- Windows7下安装Scala 2.9.2教程
- play for scala 实现SessionFilter 过滤未登录用户跳转到登录页面
- Scala小程序详解及实例代码
- Scala代码实现列出Hadoop 文件夹下面的所有文件
- ClassNotFoundException:scala.PreDef$
- sbt创建web项目
- XML 文件解析--含Unicode字符的XML文件
- Scala 学习随笔
- Scala 小程序记录(学习期间的代码片段)
- Spark机器学习(二) 局部向量 Local-- Data Types - MLlib
- Spark机器学习(三) Labeled point-- Data Types
- 分分钟掌握快速排序(Java / Scala 实现)
- Scala极速入门
- Spark初探
- Scala实现REST操作
- Scala method call syntax
- 关于Scala多重继承的菱形问题
- Scala 高阶函数(high-order function)剖析
- Scala Monad Design Pattern