常用 XML 解析技术

现在的软件项目都不是独立的一个项目,都是多系统协调工作。这样的话就涉及到系统间的通讯,通讯就会跟报文传输挂上关系。系统间使用怎样的报文格式进行通讯呢?有的使用固定长度格式报文;有的使用变长格式报文;有的使用 XML格式报告。本场 Chat 主要和大家分享一下 XML 格式报文的解析。Java 是一个开源的语言,本场 Chat 将给大家介绍一下常用的 XML 解析框架及特点。

主要内容:

  • XML 的简介及一些常见概念 ;
  • Java 内置解析 XML API: DOM、SAX;
  • XML 解析框架 JDOM;
  • XML 解析框架 DOM4J;
  • XML 解析框架 XStream ;
  • 总结 。

现在的软件项目都不是独立的一个项目,都是多系统协调工作。这样的话就涉及到系统间的通讯,通讯就会跟报文传输挂上关系。系统间使用怎样的报文格式进行通讯呢?有的使用固定长度格式报文;有的使用变长格式报文;有的使用 XML 格式报告。本分享主要和大家分享一下 XML 格式报文的解析。Java 是一个开源的语言,本分享将给大家介绍一下常用的 XML 解析框架及特点。

  • XML 的简介及一些常见概念
  • Java 内置解析 XML API: DOM、SAX
  • XML 解析框架 JDOM
  • XML 解析框架 DOM4J
  • XML 解析框架 XStream
  • 总结

XML 的简介及一些常见概念

XML 的概念

XML 是 Extensible Markup Language 简称,中文翻译为可扩展标记语言。XML 是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性,给数据集成与交互带来了极大的方便。XML 在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。

XML 可用来描述数据、存储数据、传输数据/交换数据。

XML 文档节点的类型主要有:

  1. document:文档,代表整个文档(DOM 树的根节点);
  2. element:元素,表示一个元素;
  3. attribute:属性,代表一个属性;
  4. PCDATA(Parsed Character Data):文本;
  5. comment:注释,代表一个注释;
  6. DOCTYPE:主要验证文档内容的正确性;
  7. ENTITIES:实体;
  8. CDATA(Character Data):代表文档中的 CDATA 区段,文本不会被解析器解析。
XML 的基本语法

在使用过程中,请记住以下几个基本语法。

  • 声明格式,如下:
<?xml version="1.0" encoding="UTF-8"?>  
  • 根节点:必须有一个根节点。
  • 标签:标签必须有结束且区分大小写,标签必须顺序嵌套。
  • 属性:必须使用引号引起值。
  • 空格会被保留。
  • 命名规则:命名必须见名知意。
    • 名字可包含字母、数字以及其他的字符。
    • 名字不能以数字或者标点符号开始。
    • 名字不能以字符“xml”(或者 XML、Xml)开始。
  • 名字不能包含空格。
  • 不应在 XML 元素名称中使用“:” ,这是由于它用于命名空间(NameSpaces)的保留字。
  • 标签优先于属性。
  • XML 命名空间可提供避免元素命名冲突的方法。
  • CDATA:字符数据,<![CDATA[字符数据]]> ,字符数据不进行转义。
  • 实体:使用方式为“&实体;”,XML 中有5个预定义的实体,如下表所示。
实体名称含义备注
<<小于
>>大于
&&和号
''单引号
""引号

注释:在 XML 中,只有字符 "<" 和 "&" 确实是非法的。大于号是合法的,但是用实体引用来代替它是一个好习惯。

XML 约束

1.XML DTD 约束

DTD 是 DocType Definition 的简称,中文翻译为文档类型定义,DTD 的作用是定义 XML 文档的合法构建模块。它使用一系列的合法元素来定义文档结构,用于约定 XML 的格式。规定了文档中所使用的元素、实体、元素的属性、元素与实体之间的关系。

DTD主要作用有:

  • 使用 DTD 可以提供一种统一的格式。

XML 的可扩展性为文档的作者提供了很高的灵活性,可有时候需要的是统一,要求某一类文档具有相同的结构。

  • 使用 DTD 可以保证数据交流和共享的顺利进行。
  • DTD 使用户能够不依赖具体的数据就知道文档的逻辑结构。

在没有 XML 文档的时候,也可以根据 DTD 为 XML 文档编写样式单,编写处理程序,这样可以有效地提高工作效率。

  • 使用 DTD 可以验证数据的有效性。

DTD 对文档的逻辑结构进行了约束,这种约束可以比较宽松,也可以十分严格。可以根据 DTD 检查数据,以验证其是否符合规定和要求,这可以保证数据的正确和有效。

DTD 主要定义方式:

(1)内部定义法,DTD 文件放在 XML 文件内部。

 <!DOCTYPE 根元素 [元素声明]>  

请看下面的例子,book.xml:

    <?xml version="1.0" encoding="UTF-8" ?>    <!DOCTYPE bookstore [    <!ELEMENT bookstore (book+)>    <!ELEMENT book (bookname,author,price)>    <!ATTLIST book id CDATA #REQUIRED>    <!ELEMENT bookname (#PCDATA)>    <!ELEMENT author (#PCDATA)>    <!ELEMENT price (#PCDATA)>    ]>    <bookstore>    <book>            <bookname>带你飞培训教程</bookname>            <author>huangjinjin</author>            <price>1.00元</price>    </book>    <book>            <bookname>降龙十八讲秘籍</bookname>            <author>洪七公</author>            <price>0.01元</price>    </book>    </bookstore>

(2)外部定义,请看下面这个例子。

bookstore.dtd:

    <?xml version="1.0" encoding="UTF-8"?>      <!DOCTYPE bookstore [      <!ELEMENT bookstore (book+)>      <!ELEMENT book (bookname,author,price)>      <!ATTLIST book id CDATA #REQUIRED>      <!ELEMENT bookname (#PCDATA)>      <!ELEMENT author (#PCDATA)>      <!ELEMENT price (#PCDATA)>      ]>  

book.xml:

    <?xml version="1.0" encoding="UTF-8" ?>    <!DOCTYPE bookstore SYSTEM "bookstore.dtd">    <bookstore>    <book>            <bookname>带你飞培训教程</bookname>            <author>huangjinjin</author>            <price>1.00元</price>    </book>    <book>            <bookname>降龙十八讲秘籍</bookname>            <author>洪七公</author>            <price>0.01元</price>    </book>    </bookstore>

2.XML Schema 约束

XML Schema 是基于 XML DTD 的替代者,XML Schema 描述 XML 文档的结构。XML Schema 语言也称作 XML Schema 定义(XML Schema Definition 简称 XSD)。DTD 不是通过 XML 语法定义文档结构,不能定义数据类型和限制;Schema 通过 XML 语法定义文档结构,可以定义数据类型和限制。

XML Schema 对 XML 文件的主要约定有:

  • 定义可出现在 XML 文档中的元素;
  • 定义可出现在 XML 文档中的属性;
  • 定义哪个元素是子元素;
  • 定义子元素的次序;
  • 定义子元素的数目;
  • 定义元素是否为空,或者是否可包含文本;
  • 定义元素和属性的数据类型;
  • 定义元素和属性的默认值以及固定值。

为何使用 Schema,原因有几下几点:

  • XML Schema 可针对未来的需求进行扩展;
  • XML Schema 更完善,功能更强大;
  • XML Schema 基于 XML 编写;
  • XML Schema 支持数据类型和限制;
  • XML Schema 支持命名空间。

我们看下面这个例子。

book.xsd 文件:

    <?xml version="1.0" encoding="UTF-8"?>    <schema xmlns="http://www.w3.org/2001/XMLSchema"     targetNamespace="http://www.mybook.org/BookSchema"    xmlns:tns="http://www.mybook.org/BookSchema" elementFormDefault="qualified">        <!-- 定义一个标签 -->        <element name="bookstore">            <!-- 复合类型 就是该标签含有子标签 -->            <complexType>                <!-- 含有不限定个数的子标签 -->                <sequence maxOccurs="unbounded">                    <!-- 定义一个子标签 -->                    <element name="book">                        <complexType>                            <sequence>                                <!-- 定义一个文本子标签 -->                                <element name="bookname" type="string" />                                <element name="author" type="string" />                                <element name="price" type="string" />                            </sequence>                            <attribute name="id" type="string"></attribute>                        </complexType>                    </element>                </sequence>            </complexType>        </element>    </schema>
  

book.xml

    <?xml version="1.0" encoding="UTF-8" ?>    <bookstore        xmlns="http://www.w3.org/2001/XMLSchema-instance"        xmlns:nsbook="http://www.mybook.org/BookSchema"        nsbook:schemaLocation="http://www.mybook.org/BookSchema book.xsd">        <book id="1">            <bookname>带你飞培训教程</bookname>            <author>huangjinjin</author>            <price>1.00元</price>        </book>        <book id="2">            <bookname>降龙十八讲秘籍</bookname>            <author>洪七公</author>            <price>0.01元</price>        </book>    </bookstore>

Java 内置解析 XML API: DOM、SAX

DOM

DOM的全称是 Document Object Model,即文档对象模型,W3C 组织推荐处理 XML 的一种方式。在应用程序中,基于 DOM 的 XML 分析器将一个 XML 文档转换成一个对象模型的集合(通常称 DOM 树),应用程序正是通过对这个对象模型的操作,来实现对 XML 文档数据的操作。通过 DOM 接口,应用程序可以在任何时候访问 XML 文档中的任何一部分数据,因此这种利用 DOM 接口的机制也被称作随机访问机制。

DOM 接口提供了一种通过分层对象模型来访问 XML 文档信息的方式,这些分层对象模型依据 XML 的文档结构形成了一棵节点树。无论 XML 文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用 DOM 所生成的模型都是节点树的形式。也就是说 DOM 强制使用树模型来访问 XML 文档中的信息。由于 XML 本质上就是一种分层结构,所以这种描述方法是相当有效的。

DOM 树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个 XML 文档中的内容。然而,由于 DOM 分析器把整个 XML 文档转化成 DOM 树放在了内存中,因此当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且对于结构复杂的树的遍历也是一项耗时的操作。所以 DOM 分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于 DOM 分析器所采用的树结构的思想与 XML 文档的结构相吻合,同时鉴于随机访问所带来的方便,因此 DOM 分析器还是有很广泛的使用价值的。

其优点主要有:

  1. 形成了树结构,有助于更好的理解、掌握,且代码容易编写。
  2. 解析过程中,树结构保存在内存中,方便修改。

其缺点主要有:

  1. 由于文件是一次性读取,所以对内存的耗费比较大。
  2. 如果 XML 文件比较大,容易影响解析性能且可能会造成内存溢出。

DOM 操作 XML 例子,请见下面代码:

    // 创建一个DocumentBuilderFactory的对象    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();    // 创建一个DocumentBuilder的对象    try {        // 创建DocumentBuilder对象        DocumentBuilder db = dbf.newDocumentBuilder();        // 通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下        Document document = db.parse("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\3.xml");        // 获取所有book节点的集合        NodeList bookList = document.getElementsByTagName("book");        // 通过nodelist的getLength()方法可以获取bookList的长度        System.out.println("一共有" + bookList.getLength() + "本书");        // 遍历每一个book节点        for (int i = 0; i < bookList.getLength(); i++) {            System.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容=================");            // 通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始            Node book = bookList.item(i);            // 获取book节点的所有属性集合            NamedNodeMap attrs = book.getAttributes();            System.out.println("第 " + (i + 1) + "本书共有" + attrs.getLength() + "个属性");            // 遍历book的属性            for (int j = 0; j < attrs.getLength(); j++) {                // 通过item(index)方法获取book节点的某一个属性                Node attr = attrs.item(j);                // 获取属性名 值                System.out.print("属性名:" + attr.getNodeName()+", 属性值" + attr.getNodeValue());            }            // 解析book节点的子节点            NodeList childNodes = book.getChildNodes();            // 遍历childNodes获取每个节点的节点名和节点值            System.out.println("第" + (i + 1) + "本书共有" + childNodes.getLength() + "个子节点");            for (int k = 0; k < childNodes.getLength(); k++) {                // 区分出text类型的node以及element类型的node                if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {                    // 获取了element类型节点的节点名                    System.out.print("第" + (k + 1) + "个节点的节点名:" + childNodes.item(k).getNodeName());                    // 获取了element类型节点的节点值                    System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue());                }            }            System.out.println("======================结束遍历第" + (i + 1) + "本书的内容=================");        }    } catch (Exception e) {        e.printStackTrace();    }
SAX

SAX 的全称是 Simple APIs for XML,即 XML 简单应用程序接口。与 DOM 不同,SAX 提供的访问模式是一种顺序模式,这是一种快速读写 XML 数据的方式。当使用 SAX 分析器对 XML 文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对 XML 文档的访问,因而 SAX 接口也被称作事件驱动接口。SAX 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。

其优点主要有:

  1. 采用事件驱动模式,对内存耗费比较小。
  2. 适用于只处理 XML 文件中的数据时。

其缺点主要有:

  1. 编码比较麻烦。
  2. 很难同时访问 XML 文件中的多处不同数据。

SAX 处理 XML 例子,请见下面代码:

        // 获取Sax解析工程对象        SAXParserFactory factory = SAXParserFactory.newInstance();        try {            SAXParser parser = factory.newSAXParser();            // 新建xml处理器            SAXParserHandler handler = new SAXParserHandler();            parser.parse("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\3.xml", handler);            System.out.println("共有" + handler.getBookList().size() + "本书");            for (Book book : handler.getBookList()) {                System.out.println(book.getId());                System.out.println(book.getBookname());                System.out.println(book.getAuthor());                System.out.println(book.getPrice());            }        } catch (Exception e) {            e.printStackTrace();        }

XML 处理器 SAXParserHandler 关键代码,如下:

        /**             * 解析xml元素             */        @Override        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {            // 调用DefaultHandler类的startElement方法            super.startElement(uri, localName, qName, attributes);            if (qName.equals("book")) {                bookIndex++;                // 创建一个book对象                book = new Book();                // 开始解析book元素的属性                System.out.println("============开始遍历某一本书的内容=================");                // 不知道book元素下属性的名称以及个数,如何获取属性名以及属性值                int num = attributes.getLength();                for (int i = 0; i < num; i++) {                    System.out.print("book元素的第" + (i + 1) + "个属性名是:" + attributes.getQName(i));                    System.out.println(", 属性值是:" + attributes.getValue(i));                    if (attributes.getQName(i).equals("id")) {                        book.setId(attributes.getValue(i));                    }                }            } else {                System.out.print("节点名是:" + qName +", ");            }        }        @Override        public void endElement(String uri, String localName, String qName) throws SAXException {            // 调用DefaultHandler类的endElement方法            super.endElement(uri, localName, qName);            // 判断是否针对一本书已经遍历结束            if (qName.equals("book")) {                bookList.add(book);                book = null;                System.out.println("===========结束遍历某一本书的内容=================");            } else if (qName.equals("bookname")) {                book.setBookname(value);            } else if (qName.equals("author")) {                book.setAuthor(value);            }  else if (qName.equals("price")) {                book.setPrice(value);            }         }        @Override        public void characters(char[] ch, int start, int length) throws SAXException {            super.characters(ch, start, length);            value = new String(ch, start, length);            if (!value.trim().equals("")) {                System.out.println("节点值是:" + value);            }        }

XML 解析框架 JDOM

JDOM 目的是成为 Java 特定文档模型,简化与 XML 的交互并且比使用 DOM 实现更快。由于是第一个 Java 特定模型,所以 JDOM 一直得到大力推广和促进。正在考虑通过“Java 规范请求 JSR-102”将它最终用作“Java 标准扩展”。从2000年初就已经开始了 JDOM 开发。JDOM 与 DOM 主要有两方面不同。第一,JDOM 仅使用具体类而不使用接口,这在某些方面简化了 API,但是也限制了灵活性;第二,API 大量使用了 Collections 类,简化了那些已经熟悉这些类的 Java 开发者的使用。

JDOM 文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML 问题”。JDOM 对于大多数 Java/XML 应用程序来说非常有用,并且大多数开发者发现 API 比 DOM 容易理解得多。JDOM 还包括对程序行为的相当广泛检查以防止用户做任何在 XML 中无意义的事。然而它仍需要您充分理解 XML 以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习 DOM 或 JDOM 接口都更有意义的工作。JDOM 自身不包含解析器。它通常使用 SAX2 解析器来解析和验证输入 XML 文档,尽管它还可以将以前构造的 DOM 表示作为输入。它包含一些转换器以将 JDOM 表示输出成 SAX2 事件流、DOM 模型或 XML 文本文档。JDOM 是在 Apache 许可证变体下发布的开放源码。同时需要注意的是 JDOM 目前分为两个版本,分别为JDOM 1.x 和 JDOM 2.x。

其主要特征有:

  1. 仅使用具体类,而不使用接口。
  2. API 大量使用了 Collections 类。

JDOM 解析 XML 的例子,如下:

    import java.io.File;    import java.io.FileInputStream;    import java.util.List;    import org.jdom2.Document;    import org.jdom2.Element;    import org.jdom2.input.SAXBuilder;    public class JDomTest {        public static void main(String[] args) {            try {                // 创建一个SAXBuilder对象                SAXBuilder sb = new SAXBuilder();                File file = new File("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\1.xml");                FileInputStream in = new FileInputStream(file);                // 构造文档对象                Document doc = sb.build(in);                // 获取根元素bookstore                Element root = doc.getRootElement();                // 取名字为book的所有元素                List<Element> books = root.getChildren("book");                for (int i = 0; i < books.size(); i++) {                    Element e = books.get(i);                    List<Element> sube = e.getChildren();                    System.out.println("第" + (i + 1) + "本书信息:");                    e = sube.get(0);                    System.out.println(e.getName() + "=" + e.getText());                    e = sube.get(1);                    System.out.println(e.getName() + "=" + e.getText());                    e = sube.get(2);                    System.out.println(e.getName() + "=" + e.getText());                }            } catch (Exception e) {                e.printStackTrace();            }        }    }

XML 解析框架 DOM4J

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

为支持所有这些功能,DOM4J 使用接口和抽象基本类方法。DOM4J 大量使用了 API 中的 Collections 类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然 DOM4J 付出了更复杂的 API 的代价,但是它提供了比 JDOM 大得多的灵活性。在添加灵活性、XPath 集成和对大文档处理的目标时,DOM4J 的目标与 JDOM 是一样的:针对 Java 开发者的易用性和直观操作。它还致力于成为比 JDOM 更完整的解决方案,实现在本质上处理所有 Java/XML 问题的目标。在完成该目标时,它比 JDOM 更少强调防止不正确的应用程序行为。

DOM4J 是一个非常非常优秀的 Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的 Java 软件都在使用 DOM4J 来读写 XML,特别值得一提的是 Sun 的 JAXM 也在用 DOM4J。同时需要注意的是 DOM4J 目前也分为两个版本,分别为 DOM4J 1.x和 DOM4J 2.x。

其特征主要有:

  1. JDOM 的一种智能分支,它合并了许多超出基本 XML 文档表示的功能。
  2. 它使用接口和抽象基本类方法。
  3. 具有性能优异、灵活性好、功能强大和极端易用的特点。
  4. 是一个开放源码的文件。

DOM4J 解析 XML 的例子,如下:

    import java.io.File;    import java.util.Iterator;    import java.util.List;    import org.dom4j.Attribute;    import org.dom4j.Document;    import org.dom4j.Element;    import org.dom4j.io.SAXReader;    public class DOM4JTest {        public static void main(String[] args) {            try {                // 创建SAXReader的对象reader                SAXReader reader = new SAXReader();                // 通过reader对象的read方法加载books.xml文件,获取docuemnt对象。                Document document = reader.read(                        new File("C:\\Users\\Administrator\\Desktop\\xmlchat\\xml-chat\\src\\test\\resources\\1.xml"));                // 通过document对象获取根节点bookstore                Element element = document.getRootElement();                // 通过element对象的elementIterator方法获取迭代器                Iterator<Element> iter = element.elementIterator();                int index = 0;                // 遍历迭代器,获取根节点中的信息(书籍)                while (iter.hasNext()) {                    Element e = iter.next();                    System.out.println("第" + (index + 1) + "本书");                    List<Attribute> bookAttrs = e.attributes();                    for (Attribute attr : bookAttrs) {                        System.out.println("属性名:" + attr.getName() + ",属性值:" + attr.getValue());                    }                    index = index + 1;                    Iterator<Element> siter = e.elementIterator();                    while (siter.hasNext()) {                        e = siter.next();                        System.out.println(e.getName() + "=" + e.getStringValue());                    }                }            } catch (Exception e) {                e.printStackTrace();            }        }    }

XML解析框架 XStream

XStream 是一种 OXMapping 技术,是用来处理 XML 文件序列化的框架,将 JavaBean 序列化或将 XML 文件反序列化,不需要其它辅助类和映射文件,使得 XML 序列化不再繁索。另外,Xstream 也可以将 JavaBean 序列化成 Json 或反序列化,使用非常方便。Java 自带的 JAXB(Java Architecture for XML Binding) API 也有相应的功能。下面分别介绍下这两种 API 的使用方法。

JAXB 介绍

JAXB 相关的重要 Class 和 Interface 有:

  • JAXBContext 类,是应用的入口,用于管理 XML/Java 绑定信息。
  • Marshaller 接口,将 Java 对象序列化为 XML 数据。
  • Unmarshaller 接口,将 XML 数据反序列化为 Java 对象。

JDK 中 JAXB 相关的重要 Annotation有:

  • @XmlType,将 Java 类或枚举类型映射到 XML 模式类型。
  • @XmlAccessorType(XmlAccessType.FIELD),控制字段或属性的序列化。FIELD 表示 JAXB 将自动绑定 Java 类中的每个非静态的(static)、非瞬态的(由 @XmlTransient 标注)字段到 XML。其他值还有 XmlAccessType.PROPERTY 和 XmlAccessType.NONE。
  • @XmlAccessorOrder,控制 JAXB 绑定类中属性和字段的排序。
  • @XmlJavaTypeAdapter,使用定制的适配器(即扩展抽象类 XmlAdapter 并覆盖 marshal()和 unmarshal()方法),以序列化 Java 类为 XML。
  • @XmlElementWrapper,对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的 XML 元素(称为包装器)。
  • @XmlRootElement,将 Java 类或枚举类型映射到 XML 元素。
  • @XmlElement,将 Java 类的一个属性映射到与属性同名的一个 XML 元素。
  • @XmlAttribute,将 Java 类的一个属性映射到与属性同名的一个 XML 属性。

注意以下几点:

  • 对于要序列化(marshal)为 XML 的 Java 类,绝不能把成员变量声明为 public,否则运行将抛出异常 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException
  • 对于 JAXB 相关的重要 Annotation 的声明,如 @Xml.....,可以放在成员变量的 setter() 或 getter() 方法上,两者中任选其一即可,但决不能放在成员变量上,否则运行将抛出异常 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException

我们看一个例子,Book2.java 对象:

    import javax.xml.bind.annotation.XmlAttribute;    import javax.xml.bind.annotation.XmlElement;    import javax.xml.bind.annotation.XmlRootElement;    @XmlRootElement    public class Book2 {        private String id;        private String bookname;        private String author;        private String price;        public String getId() {            return id;        }        @XmlAttribute        public void setId(String id) {            this.id = id;        }        public String getBookname() {            return bookname;        }        @XmlElement        public void setBookname(String bookname) {            this.bookname = bookname;        }        public String getAuthor() {            return author;        }        @XmlElement        public void setAuthor(String author) {            this.author = author;        }        public String getPrice() {            return price;        }        @XmlElement        public void setPrice(String price) {            this.price = price;        }    }

将 JavaBean 转成 XML,如下:

    import java.io.FileOutputStream;    import java.io.StringWriter;    import javax.xml.bind.JAXBContext;    import javax.xml.bind.Marshaller;    //将java bean转成xml    public class JaxbMarshal {        public static void main(String[] args) {            try {                Book2 book = new Book2();                book.setId("1");                book.setAuthor("千年老二");                book.setBookname("葵花宝典");                book.setPrice("1234");                JAXBContext context = JAXBContext.newInstance(Book2.class);                Marshaller m = context.createMarshaller();                StringWriter sw = new StringWriter();                m.marshal(book, sw);                m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化                m.marshal(book, new FileOutputStream("src/main/java/book.xml"));                System.out.println(sw.toString());            } catch (Exception e) {                e.printStackTrace();            }        }    }

将 XML 转成 JavaBean,如下:

    import java.io.File;    import javax.xml.bind.JAXBContext;    import javax.xml.bind.Unmarshaller;    //将xml转成java bean    public class JaxbUnMarshal {        public static void main(String[] args) {            try {                JAXBContext context = JAXBContext.newInstance(Book2.class);                Unmarshaller m = context.createUnmarshaller();                Book2 book = (Book2)m.unmarshal(new File("src/main/java/book.xml"));                System.out.println(book.getId());                System.out.println(book.getBookname());                System.out.println(book.getAuthor());                System.out.println(book.getPrice());            } catch (Exception e) {                e.printStackTrace();            }        }    }
XStream 介绍

XStream 是个很强大的工具,能将 Java 对象和 XML 之间相互转化。XStream 不在意 Java 类中成员变量是私有还是公有,也不在乎是否有默认构造函数。它调用方式也非常简单:从 XML 对象转化为 Java 对象,使用 fromXML() 方法;从 Java 对象序列化为 XML,toXML() 即可,很方便。XStream 也支持注解方式,这些都是为了简化输出而设计。

XStream常用注解说明有:

  • @XStreamAlias 注解可在类与属性上,设置别名;
  • @XStreamAliasType 注解设置在类,设置类型别名;
  • @XStreamAsAttribute 注解设置在属性上,作用是将类内成员作为父节点属性输出;
  • @XStreamConverter 注解设置在属性上,注入转化器;
  • @XStreamConverters 注解设置在属性上,注入多个转化器;
  • @XStreamImplicit 常用在集合属性上,表明只把集合里的元素列序号到 XML中;
  • @XStreamInclude
  • @XStreamOmitField 注解可设置在属性上,表明该属性不会被序列化到 XML 中。

接下来,我们看下 XStream 使用例子。

Person 实体类,如下:

    import com.thoughtworks.xstream.annotations.XStreamAlias;    import com.thoughtworks.xstream.annotations.XStreamAliasType;    import com.thoughtworks.xstream.annotations.XStreamAsAttribute;    import com.thoughtworks.xstream.annotations.XStreamOmitField;    @XStreamAliasType("p")    public class Person    {        @XStreamAsAttribute        private int id;        @XStreamAlias("n")        private String name;        @XStreamAlias("a")        @XStreamOmitField        private int age;        public String getName() {            return name;        }        public void setName(String name) {            this.name = name;        }        public int getAge() {            return age;        }        public void setAge(int age) {            this.age = age;        }    }

XStream 操作 XML,如下:

    import com.thoughtworks.xstream.XStream;    public class XStreamTest {        public static void main(String[] args)        {            Person person=new Person();            person.setName("独孤求败");            person.setAge(100);            XStream xstream = new XStream();            // 进行注解的检测  如果没有这行注解将不起作用            xstream.autodetectAnnotations(true);             //XML序列化            String xml = xstream.toXML(person);            System.out.println(xml);            //XML反序列化            Person person1=(Person)xstream.fromXML(xml);            System.out.println(person1.getName());            System.out.println(person1.getAge());        }    }

备注: xstream.autodetectAnnotations(true) 的作用是开启注解扫描,如果没有改行代码,默认为 false,不开启注解扫描,这样的话 Person.java 将不起任何作用。

总结

我们综合看下 DMO、SAX 和 JDOM 三者之间的区别。

(1)DOM:拉模型,把整个文档加载到内存中。

  • 优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;
  • 缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;
  • 使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。

(2)SAX:推模型,事件驱动编程,基于回调 SAX ,事件驱动。当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。

  • 优点:不用事先调入整个文档,占用资源少;
  • 缺点:不是持久的;事件过后,若没保存数据,那么数据就丢了;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;
  • 使用场合:数据量较大的XML文档,占用内存高,机器内存少,无法一次加载XML到内存;只需XML文档的少量内容,很少回头访问;

(3)JDOM:为减少 DOM、SAX 的编码量,出现了 JDOM。

  • 优点:20-80原则,极大减少了代码量,提供常用 API 减少重复劳动;
  • 使用场合:要实现的功能简单,如解析、创建等Java程序。

再来看下三者之间的性能比较。

(1)DOM4J 性能最好,连 Sun 的 JAXM 也在用 DOM4J。目前许多开源项目中大量采用 DOM4J,例如大名鼎鼎的 Hibernate 也用 DOM4J 来读取 XML 配置文件。如果不考虑可移植性,那就采用 DOM4J。

(2)JDOM 和 DOM 在性能测试时表现不佳,在测试 10M 文档时内存溢出。在小文档情况下还值得考虑使用 DOM 和 JDOM。虽然 JDOM 的开发者已经说明 他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM 仍是一个非常好的选择。DOM 实现广泛应用于多种编程语言。它还是许多其它与 XML 相关的标准的基础,因为它正式获得 W3C 推荐(与基于非标准的 Java 模型相对),所以在某些类型的项目中可能也需要它(如在 JavaScript 中使用 DOM)。

(3)SAX 表现较好,这要依赖于它特定的解析方式——事件驱动。一个 SAX 检测即将到来的 XML 流,但并没有载入到内存(当然当 XML 流被读入时,会有部分文档暂时隐藏在内存中)。

这里提供下源码地址:https://gitee.com/hjj520/xml,大家可以自行下载学习。


本文首发于GitChat,未经授权不得转载,转载需与GitChat联系。

阅读全文: http://gitbook.cn/gitchat/activity/5aa3ab85291bf90af9b04b2c

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

FtooAtPSkEJwnW-9xkCLqSTRpBKX

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值