天天看点

XML与JAVA

XML

简介

XML,全称为eXtensible Markup Language,即可扩展标记语言。其被设计用来传输及存储数据。XML与HTML看似比较相似,但是其设计目的并不相同。

XML用来传输及存储数据,主要关注数据是什么。

HTML用来显示数据,主要关注数据看起来是什么样。

HTML的tag是预定义的,比如说table标签,浏览器会知道它是什么含义。

XML的tag不是预定义的,需要自己设计tag并描述tag的含义。XML中的tag如果不借助XSLT文件,浏览器只会以简单的文本方式展示。

HTML不是XML文件的一个子集。因为HTML的实现并未严格遵循XML的语法。比如XML要求每个tag必须要有闭合标记,大小写敏感的,tag属性必须要使用引号包起来…这些语法要求HTML都不满足。

<?xml version="1.0" encoding="ISO-8859-1"?>
<book>
    <name>Effective JavaScript</name>
    <category>Program Language</category>
    <author>Bowen</author>
    <description>This book is about JavaScript Language.</description>
</book>      

xml文件的第一行说明xml的版本及编码类型。

命名空间

XML的tag可以自定义,HTML是预定义;两个XML中的同名tag具有不同的含义,在合并XML等操作时势必会造成冲突。解决办法就是给XML的tag加上命名空间namespace,每一个namespace都可以指定一个前缀。这些前缀会区分同名tag。

​​

​ns1:book xmlns:ns1="http://www.aaa.net/ns1"​

​​ xmlns是xml namespace。引号后面是tag的前缀,可以省略,比如xmlns=“​​http://www.aaa.net/ns1​​”,相当于没有前缀的tag自动应用默认的命名空间。命名空间的URI只是给命名空间提供一个唯一的标识,xml解析器并不会访问这个URI来获取任何信息。很多公司习惯将这个URI一个web页面,该web页面描述该namespace的相关信息。

XSD

XSD全称为XML Schema Definition,即XML结构定义语言。每个XSD文件是对一个XML文件的结构定义。由于XML中的tag并不是预定义的,那么每人都可以创建自己的XML结构文档。如果你想让别人按照你的标准创建一份xml文件,你可以使用XSD文件来描述你的标准。XSD文件本身就是一个XML文件,它遵循XML语法,比如每个tag都需要有结束标记,必须有且只有一个根节点等。在IDE中,如果你的XML节点没有遵守你引用的Schema中的定义,就会给出错误提醒。

XSLT

XSLT全称为EXtensible Stylesheet Language Transformations。XSLT用于将XML文档转换为XHTML或其他XML文档。XSL全称为Extensible Stylesheet Language,即可扩展样式表语言。CSS是HTML文件的样式表,而XSL则是XML文件的样式表。XSL文件描述XML文件应该如何被显示。其实XSL不仅仅是样式表语言,它主要包含3部分:

  • XSLT - 用来转换XML文档
  • XPath - 查询和操作XML文档中的节点
  • XSL-FO - 格式化XML文档

XSLT使用XPath来查找XML中的元素。XSLT通过一个xml文件来定义源xml文件与目标文件之间的转换关系。该xml文件必须以或作为根节点。对于没有引用XSLT文件的xml文件,chrome浏览器打开之后,看到的是纯文本。引入​

​<?xml-stylesheet type="text/xsl" href="book.xsl"?>​

​​之后,浏览器可以看到格式化之后的美化文件。注意:可能需要设置chrome的–allow-file-access-from-files属性,这样chrome才允许加载本地的xsl文件。

​​​http://stackoverflow.com/questions/3828898/can-chrome-be-made-to-perform-an-xsl-transform-on-a-local-file​​

DOM

Document Object Model,

DTD

Document Type Definition

SAX

Simple API for XML

XPath

简介:XPath包含一个标准函数库,含有超过 100 个内建的函数,用于字符串值、数值、日期和时间比较、节点和 QName 处理、序列处理、逻辑值等;是 XSLT 中的主要元素,XQuery 和 XPointer 均构建于 XPath 表达式之上。XQuery 1.0 和 XPath 2.0 共享相同的数据模型,支持相同的函数和运算符;是W3C标准,XPath 被设计为供 XSLT、XPointer 以及其他 XML 解析软件使用;XPath 使用路径表达式在 XML 文档中进行导航,选取 XML 文档中的节点或者节点集。

基本概念

在 XPath 中,有七种类型的节点Node:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。

示例文档

<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
  <title lang="en">Harry Potter</title>
  <price>29.99</price>
</book>
<book>
  <title lang="en">Learning XML</title>
  <price>39.95</price>
</book>
</bookstore>      

bookstore文档节点,price是元素节点,lang=“en” 是属性节点 ;

基本值(原子值,Atomic value):基本值是无父或无子的节点。

项目(Item):项目是基本值或者节点。

节点关系

父(Parent):每个元素以及属性都有一个父。

子(Children):元素节点可有零个、一个或多个子。

同胞(Sibling) :拥有相同的父的节点

先辈(Ancestor):某节点的父、父的父等。

后代(Descendant):某个节点的子,子的子等。

路径表达式

XPath 是一门使用路径表达式在 XML文档中查找信息(节点或节点集)的语言,用于在 XML 文档中通过元素和属性进行导航。节点是通过沿着路径path或者步step来选取的,路径均包括一个或多个步,每个步均被斜杠分割。谓语Predicates,用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。谓语支持的函数:last(),position()❤️,price>35.00等。通配符可用来选取未知的 XML 元素,​

​*​

​​:匹配任何元素节点;​

​@*​

​​:匹配任何属性节点;node():匹配任何类型的节点。使用​

​|​

​​运算符选取若干个路径。位置路径可以是绝对或者相对的。绝对路径起始于正斜杠( / )。

绝对位置路径:/step/step/…

相对位置路径:step/step/…

每个步均根据当前节点集之中的节点来进行计算。

步step的语法:轴名称::节点测试[谓语]。谓语可以有多个。其中,节点测试(node-test)用于识别某个轴内部的节点,谓语更深入地提炼所选的节点集。

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
选取当前节点的父节点。
@ 选取属性。
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

XPath 轴

轴可定义相对于当前节点的节点集,即所选节点与当前节点之间的树关系。

轴名称 结果
ancestor 选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素(子、孙等)。
descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
preceding 选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling 选取当前节点之前的所有同级节点。
self 选取当前节点。

step示例以及解释

例子 结果
child::book 选取所有属于当前节点的子元素的 book 节点。
attribute::lang 选取当前节点的 lang 属性。
child:? 选取当前节点的所有子元素。
attribute:? 选取当前节点的所有属性。
child::text() 选取当前节点的所有文本子节点。
child::node() 选取当前节点的所有子节点。
descendant::book 选取当前节点的所有 book 后代。
ancestor::book 选择当前节点的所有 book 先辈。
ancestor-or-self::book 选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点)
child:?/child::price 选取当前节点的所有 price 孙节点。

参考:

​​​XPath教程​​

xml vs json vs yaml

XML解析

XML的开源解析工具不要太多:Xerces、JDOM、DOM4J、XOM、JiBX、KXML、XMLBeans、jConfig、XStream、XJR等。但是解析方式总结来说,主要是三种:dom、sax、pull。

DOM

DOM是一种文档对象模型;DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准,以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构做出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。

为 XML 文档的已解析版本定义一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后就可以使用 DOM 接口来操作这个树结构。适用场合:一旦解析文档还需多次访问这些数据;硬件资源充足(内存、CPU)。

优点:DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构,DOM技术使得用户页面可以动态的变化,如动态显示、隐藏一个元素,改变它的属性,增加元素等,DOM可以使页面的交互性大大增强。整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;

缺点:将整个文档以文档树方式调入内存(包括无用的节点),浪费时间和空间。

SAX

SAX是一个用于处理XML事件驱动的推模型,解决DOM占用内存的问题;SAX处理的优点非常类似于流媒体。分析能够立即开始,而无需等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。适用于大型文档。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX比DOM快许多。

当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。

优点:不用事先调入整个文档,解析速度快,占用内存少,按需加载和解析文档内容。

缺点:不是持久的;事件过后,若没保存数据,数据丢失;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;只需XML文档的少量内容,很少回头访问;机器内存少;它不会记录标签的关系,而是需要应用程序自己处理,这样就会增加程序的负担。

PULL

pull和sax很相似,区别:pull读取XML文件后触发相应的事件调用方法返回的是数字,且pull可以在程序中控制,想解析到哪里就可以停止解析。(SAX解析器的工作方式是自动将事件推入事件处理器进行处理,因此你不能控制事件的处理主动结束;而Pull解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析。pull是一个while循环,随时可以跳出,而sax不是,sax是只要解析,就必须解析完成。)

如何选择?

DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。

SAX解析器采用基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。

解析工具

jaxb

在使用JAXB处理XML与JAVABEAN互相转换的问题,在不同版本的JDK中支持的功能不一样,导致有些功能不能正常处理,这就涉及到JDK支持的JAXB版本的区别。

查看JDK支持的JAXB版本方法如下:​​

​xjc -version​

​​ xjc 2.2.8-b130911.1802

JDK1.6的JAXB版本是​

​2.0.*或者2.1.*​

​, JDK1.7之后就是2.2.×××,有些功能在1.7之后的JAXB中才能使用。

jaxp

jaxp对xml文件的解析是通过xpath来实现的,核心API接口有XPath和XPathExpression,都在javax.xml.xpath包中,分别表示XPath对象以及被预编译后的表达式对象。Sun 的 JAXM 也在用 DOM4J。

jdom

JDOM也提供对XPath的支持,减少DOM、SAX的编码量;优点:20-80原则,极大减少代码量。使用场合:要实现的功能简单,如解析、创建等,但在底层,JDOM还是使用SAX(最常用)、DOM、Xanan文档。相当于sax和DOM的合体。

JDOM与DOM主要有两方面不同。首先,JDOM仅使用具体类而不使用接口。这在某些方面简化API,但是也限制灵活性。第二,API大量使用Collections类,简化那些已经熟悉这些类的Java开发者的使用。

JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题”。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。

JDOM自身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或XML文本文档。

Dom4j

Dom4j也提供对XPath的支持,与JAXP的XPathExpression作用类似的接口为org.dom4j.XPath。虽然DOM4J代表完全独立的开发结果,但最初它是JDOM的一种智能分支。它合并许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。

为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出更复杂的API的代价,但是它提供比JDOM大得多的灵活性。

在添加灵活性、XPath集成和对大文档处理的目标时,在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。

有着性能优异、功能强大和极端易用使用的特点,连Sun的JAXM也在用DOM4J。

与jaxen的关系。

XStram

XStream是一个Java对象和XML相互转换的工具,提供所有的基础类型、数组、集合等类型直接转换的支持。XStream对象相当Java对象和XML之间的转换器,转换过程是双向。使用XStream 不用任何映射就能实现多数 Java 对象的序列化。在生成的 XML 中对象名变成元素名,类中的字符串组成 XML 中的元素内容。使用 XStream 序列化的类不需要实现 Serializable 接口。XStream 是一种序列化工具而不是数据绑定工具,就是说不能从 XML 或者 XML Schema Definition (XSD) 文件生成类。 xstream不在意java类中成员变量是私有还是公有,也不在乎是否有默认构造函数。它调用方式也非常简单:从xml对象转化为java对象,使用fromXML()方法;从java对象序列化为xml,toXML()即可,很方便。xstream也支持注解方式。

和其他序列化工具相比,XStream突出的特点:

  1. XStream 不关心序列化/逆序列化的类的字段的可见性。
  2. 序列化/逆序列化类的字段不需要 getter 和 setter 方法。
  3. 序列化/逆序列化的类不需要有默认构造函数。
  4. 不需要修改类,使用 XStream 就能直接序列化/逆序列化任何第三方类

maven:

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.11.1</version>
</dependency>      

xstream提供的几个主要的注解:

  1. @XStreamAlias(“cat”) 用于类名时,等同于 xstream.alias(“cat”, Cat.class);

    xs.processAnnotations(Cat.class);​​//将Cat.class类上的注解将会使用​​,用于类对应到 xml 文件的根节点;括号里面可以指定自己想要的名称,如把驼峰命名换成大写开头的;类名com.timejob.node.Cat将替换成cat输出;用于属性时, 作用就是将属性按照别名输出,等同于xstream.aliasField(“catAge”, Cat.class, “age”);

  2. @XStreamAsAttribute 作用是将类内成员作为父节点属性输出,等同于xstream.useAttributeFor(Cat.class, “name”)。

    实例:​​

    ​<cat name="馄饨"></cat>​

  3. @XStreamImplicit 常用于集合,去除显示,只显示之间的节点元素
  4. @XStreamOmitField 表明该属性不会被序列化到xml中。

使用注解方式生成xml格式,而不是使用 xstream.toXML()方法。

//注册转换器

xstream.registerConverter(new AuthorConverter());

AuthorConverter必须符合二个条件

  1. 必须要有个默认的无参构造函数
  2. 类声明必须为:public

    不用注解这二点都可以不强制要求!

Castor