Scala入门到精通——第二十七节 Scala操纵XML
本节主要内容
- 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>
通过上面的代码不难发现,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=30val xml1= if(age<29) <age> {age} </age> else NodeSeq.Empty//<age> 28 </ageprintln(xml1)//<age> 79 </age>val xml2= <age> {29+50} </age>println(xml2)
2. XML内容提取
提取XML中的文本:
object ExtractXMLText extends App{val x= <person><name>摇摆少年梦</name><age>27</age></person>//摇摆少年梦27println(x.text)
}
这种提取方式将XML中所有的文本内容提取出来并拼接在一起,在实际中我们可能需要精确提取,比如我只想提取name元素中的内容,此时可以采用下列方式:
val x= <person><name>摇摆少年梦</name><age>27</age></person>
//提取name子结点,类型XPATH访问方式
//<name>摇摆少年梦</name>println(x \ "name") //<name>摇摆少年梦</name>
//提取name中的文本println((x \ "name").text) //摇摆少年梦scala> x \ "age"
res2: scala.xml.NodeSeq = NodeSeq(<age>27</age>)
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>//返回空NodeSeqprintln(x \ "name")// \\提取二级子元素//<name>摇摆少年梦</name><name>张三</name><name>李四</name>println(x \\ "name")
通过\和\\可以提取任何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")
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())
}
反序列化操作:
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)
}
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)
}
下面给出的是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 =
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 matchingxmlMatching(<persons><person><name>摇摆少年梦</name></person><person><name>摇摆少年梦</name></person></persons>)
}
从上述代码可以看到,<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>)
}
因为返回的是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>)
Scala入门到精通——第二十七节 Scala操纵XML相关推荐
- Scala入门到精通——第二十节 类型参数(二)
本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对Scala中的 ...
- Scala入门到精通——第二十一节 类型参数(三)-协变与逆变
本节主要内容 协变 逆变 类型通匹符 1. 协变 协变定义形式如:trait List[+T] {} .当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,即List[S] ...
- Scala入门到精通——第二十八节 Scala与JAVA互操作
本节主要内容 JAVA中调用Scala类 Scala中调用JAVA类 Scala类型参数与JAVA泛型互操作 Scala与Java间的异常处理互操作 1. JAVA中调用Scala类 Java可以直接 ...
- Scala入门到精通——第十七节 类型参数(一)
本节主要内容 类型变量界定(Type Variable Bound) 视图界定(View Bound) 上界(Upper Bound)与下界(Lower Bound) 1. 类型变量界定(Type V ...
- Scala入门到精通——第十节 Scala类层次结构、Traits初步
本节主要内容 Scala类层次结构总览 Scala中原生类型的实现方式解析 Nothing.Null类型解析 Traits简介 Traits几种不同使用方式 1 Scala类层次结构 Scala中的类 ...
- Scala入门到精通——第二十九节 Scala数据库编程
本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...
- Scala入门到精通——第二十五节 提取器(Extractor)
本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们 ...
- Scala入门到精通——第二十四节 高级类型 (三)
本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在Scala中,类(class)与类型(type)是两个不一样的概念. ...
- Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构
本节主要内容 Scala基本类型 基本类型操作 Scala程序控制结构 Scala基本类型 Scala中的基本数据类型如下图: (来源:Programming in scala) 从上表中可以看出,S ...
最新文章
- 阿里巴巴为什么能抗住90秒100亿?看完这篇你就明白了!
- R语言基于LASSO进行特征筛选(feature selection)
- 火电电厂相关业务知识
- NYOJ 485 A*B Problem
- C/Cpp / 模板类中可以使用虚函数吗?模板成员函数可以是虚函数吗?
- 20170819 - 今日技能封装 - A
- Python之调用JS的方式
- 有关 给Layout设置监听事件后,与Layout子控件的响应关系
- SQL存储过程调试方法
- 推荐一个免费绘制软件架构图的网站
- jvm 的内存分配方式
- python运维都做些什么_python运维工程师主要干什么
- uniapp引入字体包——DIN
- 福利卡巴斯基一年免费以及一些使用软件
- Yigo平台环境配置——详细步骤
- 语音转文字软件哪个好,这三款值得收藏
- 初创公司,如何找到靠谱的产品经理?
- 阿里巴巴python招聘_作为应届生,我在阿里巴巴的成功面试经历!
- 计算机上根号是哪一个,电脑上怎么哪个键是数学中的开根号啊
- ts3.03.x cocos实现九宫格/跑马灯抽奖
热门文章
- 进行面向对象设计时,就一个类而言,应该仅有一个引起它变化 的原因,这属于()设计原则。【最全!最详细解析!】
- 在word中给公式添加序号
- [leetcode] 21.合并两个有序链表
- php做的物资管理系统,基于WEB的物资管理信息系统
- Android 通过字符串来获取R下面资源的ID 值 文字资源
- Eclipse下搭建C语言开发环境
- mysql不存在就批量新增_mysql批量插入,存在则修改,不存在则插入
- 合并远程仓库到本地_使用命令行把你新建的项目上传到GitHub仓库中
- 神兽来了服务器维护,20191204维护公告解读
- 在php中页面布局 3列左右侧固定中间自适应居中,css三列布局--两边固定中间自适应和中间固定两边自适应...