使用Scala解析XML,充分体现了函数式编程的特点,简洁和明了。用Java去解析不是不行,只不过代码不够清晰明了。

首先先把XML文件读入到内存里:

val someXml = XML.loadFile("file/FIXExample.xml")

这样someXml是一个scala.xml.Elem对象。

Scala XML API提供了类似XPath的语法来解析XML。在NodeSeq这类父类里,定义了两个很重要的操作符("\"和"\\"),用来获得解析XML:

  • \ :Projection function, which returns elements of this sequence based on the string that--简单来说,\ 根据条件搜索下一子节点
  • \\:Projection function, which returns elements of this sequence and of all its subsequences, based on the string that--而 \\ 则是根据条件搜索所有的子节点

先上一个XML的文件作为例子:

<fix major="4" minor="2">
<header>
<field name="BeginString" required="Y">FIX4.2</field>
<field name="MsgType" required="Y">Test</field>
</header>
<trailer>
<field name="Signature" required="N"/>
<field name="CheckSum" required="Y"/>
</trailer>
<messages>
<message name="Logon" msgtype="A" msgcat="admin">
<field name="ResetSeqNumFlag" required="N"/>
<field name="MaxMessageSize" required="N"/>
<group name="NoMsgTypes" required="N">
<field name="RefMsgType" required="N"/>
<field name="MsgDirection" required="N"/>
</group>
</message>
<message name="ResendRequest" msgtype="2" msgcat="admin">
<field name="BeginSeqNo" required="Y"/>
<field name="EndSeqNo" required="Y"/>
</message>
</messages>
<fields>
<field number="1" name="TradingEntityId" type="STRING"/>
<field number="4" name="AdvSide" type="STRING">
<value enum="X" description="CROSS"/>
<value enum="T" description="TRADE"/>
</field>
<field number="5" name="AdvTransType" type="STRING">
<value enum="N" description="NEW"/>
</field>
</fields>
</fix>

1. 首先来个简单的,如果要找header下的field,那么这样写即可:

val headerField = someXml\"header"\"field"

2.找所有的field:

val field = someXml\\"field"

3. 找特定的属性(attribute),如找header下的所有field的name属性的值:

val fieldAttributes = (someXml\"header"\"field").map(_\"@name")

val fieldAttributes = someXml\"header"\"field"\\"@name"

两个都能找到header下面所有field的name属性,但问题是输出的格式不一样。前者会返回一个List-List(BeginString, MsgType),而后者仅仅是BeginStringMsgType。中间连空格也没有。所以建议用前一种方法获得属性。

之前以为,下面的方法,和第二种方法一样能够获得属性的值:

val fieldAttributes = someXml\"header"\"field"\"@name"

根据\操作符的定义,理论上应该可以输出name属性的。实际上输出的结果是空,什么也没有。

\操作符的源码里有这么一段:

    that match {
case "" => fail
case "_" => makeSeq(!_.isAtom)
case _ if (that() == '@' && this.length == ) => atResult
case _ => makeSeq(_.label == that)
}

第三个case表面,只有当this.length==1时,才可以这样做。原因其实很简单,somXml\"header"\"field"返回的是一个Seq[Node]的集合,包含多个对象。而\"@"的操作无法确定操作哪一个对象的属性:

  val x = <b><h id="bla"/><h id="blub"/></b>
val y = <b><h id="bla"/></b>
println(x\\"h"\"@id") //Wrong
println(y\\"h"\"@id") //Correct with output: bla

4. 查找并输出属性值和节点值的映射:

(someXml\"header"\"field").map(n=>(n\"@name", n.text, n\"@required"))

这样的输出是List((BeginString,FIX4.2,Y), (MsgType,Test,Y))

5. 有条件地查找节点,例如查找name=Logon的message:

val resultXml1 = (someXml\\"message").filter(_.attribute("name").exists(_.text.equals("Logon")))

val resultXml2 = (someXml\\"message").filter(x=>((x\"@name").text)=="Logon")

6. 通过 \\"_" 获得所有的子节点,例如:

println(resultXml1\\"_")

结果是:

<message msgcat="admin" msgtype="A" name="Logon">
<field required="N" name="ResetSeqNumFlag"/>
<field required="N" name="MaxMessageSize"/>
<group required="N" name="NoMsgTypes">
<field required="N" name="RefMsgType"/>
<field required="N" name="MsgDirection"/>
</group>
</message>
<field required="N" name="ResetSeqNumFlag"/>
<field required="N" name="MaxMessageSize"/>
<group required="N" name="NoMsgTypes">
<field required="N" name="RefMsgType"/>
<field required="N" name="MsgDirection"/>
</group>
<field required="N" name="RefMsgType"/>
<field required="N" name="MsgDirection"/>

本文完

初试Scala解析XML的更多相关文章

  1. Scala入门到精通——第二十七节 Scala操纵XML

    本节主要内容 XML 字面量 XML内容提取 XML对象序列化及反序列化 XML文件读取与保存 XML模式匹配 1. XML 字面量 XML是一种很重要的半结构化数据表示方式,眼下大量的应用依赖于XM ...

  2. Android 解析XML文件和生成XML文件

    解析XML文件 public static void initXML(Context context) { //can't create in /data/media/0 because permis ...

  3. Android之解析XML

    1.XML:可扩展标记语言. 可扩展标记语言是一种很像超文本标记语言的标记语言. 它的设计宗旨是传输数据,而不是显示数据. 它的标记没有被预定义.需要自行定义标签. 它被设计为具有自我描述性. 是W3 ...

  4. Android之Pull解析XML

    一.Pull解析方法介绍 除了可以使用SAX和DOM解析XML文件,也可以使用Android内置的Pull解析器解析XML文件.Pull解析器的运行方式与SAX解析器相似.它也是事件触发的.Pull解 ...

  5. Android之DOM解析XML

    一.DOM解析方法介绍 DOM是基于树形结构的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树,检索所需数据.分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息 ...

  6. Android之SAX解析XML

    一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...

  7. Android 使用pull,sax解析xml

    pull解析xml文件 1.获得XmlpullParser类的引用 这里有两种方法 //解析器工厂 XmlPullParserFactory factory=XmlPullParserFactory. ...

  8. 用 ElementTree 在 Python 中解析 XML

    用 ElementTree 在 Python 中解析 XML 原文: http://eli.thegreenplace.net/2012/03/15/processing-xml-in-python- ...

  9. java解析xml的三种方法

    java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXE ...

随机推荐

  1. JS全屏漂浮广告、移入光标停止移动

    点击这里查看效果 以下是代码: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Ty ...

  2. 【grunt第三弹】grunt在前端实际项目中的应用

    前言 [grunt第二弹]30分钟学会使用grunt打包前端代码(02) [grunt第一弹]30分钟学会使用grunt打包前端代码 经过前两次的学习,我们了解了grunt打包的一些基础知识,对于压缩 ...

  3. How to Operate SharePoint User Alerts with PowerShell

    When you migrate list or site, the user alerts in the site will not be migrated together with the co ...

  4. Android 自定义线程池的实战

    前言:在上一篇文章中我们讲到了AsyncTask的基本使用.AsyncTask的封装.AsyncTask 的串行/并行线程队列.自定义线程池.线程池的快速创建方式. 对线程池不了解的同学可以先看 An ...

  5. IOS开发之Bug--关于UIImageView的使用

    这里是遇到的一个关于使用UIImageView的小bug,bug就是加载不出来图片. 原因:如果图片资源是jpg文件,如果代码没有加后缀.jpg就会出现不加载出来的情况: 添加上.jpg就能加载出来了 ...

  6. 在 CentOS7 上部署 zookeeper 服务

    在 CentOS7 上部署 zookeeper 服务 1 用 SecureCRT 或 XShell 等 Linux 客户端工具连接至 CentOS7 服务器: 2 进入到 /usr/local/too ...

  7. android handler ,message消息发送方式

    1.Message msg =  Message.obtain(mainHandler) msg.obj=obj;//添加你需要附加上去的内容 msg.what = what;//what消息处理的类 ...

  8. ORACLE 移动数据文件 控制文件 重做日志文件

    ORACLE数据库有时候需要对存储进行调整,增加分区.IO调优等等,此时需要移动数据文件.重做日志文件.控制文件等等,下文结合例子总结一下这方面的知识点. 进行数据文件.重做日志文件.控制文件的迁移前 ...

  9. ORA-14452的出现原因解析及解决方法

    在删除临时表时遇到了ORA-14452错误:ORA-14452: attempt to create , alert or drop an index on temporary table alrea ...

  10. (转)tomcat进程意外退出的问题分析

    节前某个部门的测试环境反馈tomcat会意外退出,我们到实际环境排查后发现不是jvm crash,日志里有进程销毁的记录,从pause到destory的整个过程: org.apache.coyote. ...