昨天写了使用 Jackson 玩转 xml 的序列化和反序列化,主要使用的是 XmlMapper 对象去操作,今天打算尝试下使用流式 API 的方式去操作。公司墙很高,人总是在逆境中成长的对吧,墙高使得我不断输出,以便在公司里有可用的资料完成我的工作和任务,达到早日走向人生颠覆的境界。

关于 使用 Jackson 玩转 xml 的序列化和反序列化 参考我昨天写的博文

网上找了个介绍,流式API读取和写入JSON内容离散事件。 JsonParser读取数据,而JsonGenerator写入数据。它是三者(普通操作对象,树模型操作对象,流式模型操作对象)中最有效的方法,是最低开销和最快的读/写操作。它类似于XML的Stax解析器。补充一下,我认为说的挺对的,但是并不仅仅是操作 JSON 还可以操作 XML。(后面发现不支持写入 XML 带 <![CDATA[]]>, 会自动转义为 <![CDATA[]]>,还是基于注解的方式好用)

我们将展示的使用Jackson的流式API 读写XML数据。流式API工作使用 XML 为每一个细节的都是要小心处理。下面的例子将使用两个类:

ToXmlGenerator 的实例实现XML写入
FromXmlParser 的实例读取XML反序列化(网上资料很少,本人现在还不会用也不推荐用)

ToXmlGenerator 的实例实现XML写入

// 使用 stream 流式 API 操作 xml 文档
    private static void useJacksonXMLStream() throws IOException {
        // 第一步: 创建 ObjectMapper 它提供一些功能将转换成Java对象匹配JSON\XML结构,这里解析 XML 文档所以用子类  XmlMapper 它使用XMLParser和ToXmlGenerator的实例实现XML的读/写。
        ObjectMapper xmlMapper = new XmlMapper();

        // 强制JSON 空字符串("")转换为null对象值:
        // xmlMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

        // 美化输出
        // xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);

        // 第二步: 创建 ToXmlGenerator的实例实现XML写入, 由于ToXmlGenerator使用了工厂模式所以要用工厂中创建
        ToXmlGenerator toXmlGenerator = (ToXmlGenerator) xmlMapper.getFactory().createGenerator(new File("student3.xml"), JsonEncoding.UTF8);




        // ToXmlGenerator toXmlGenerator = (ToXmlGenerator) xmlMapper.getFactory().createGenerator(System.out, JsonEncoding.UTF8);
        // 流式输出美化要用这个 new DefaultXmlPrettyPrinter()
        toXmlGenerator.setPrettyPrinter(new DefaultXmlPrettyPrinter());
        toXmlGenerator.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
        /**
         * 最后写入 student3.xml 的内容为
         * <student>
         *   <cdata>中文</cdata>
         *   <age>22</age>
         *   <classroom>
         *     <grade>4</grade>
         *     <id>1</id>
         *     <name>软件工程</name>
         *   </classroom>
         *   <id>101</id>
         *   <name>张三</name>
         *   <item>1</item>
         *   <item>2</item>
         * </student>
         */
        QName student = new QName("student");
        toXmlGenerator.setNextName(student);  //<student>
        toXmlGenerator.writeStartObject();  // 写入对象开始
        toXmlGenerator.writeStringField("cdata", "<![CDATA[]]>");
        toXmlGenerator.writeStringField("age", "22");
        toXmlGenerator.writeStringField("id", "101");
        toXmlGenerator.writeStringField("name", "张三");

        int[] item1 = new int[]{1, 2};
        for (int i = 0; i < item1.length; i++) {
            toXmlGenerator.writeNumberField("item", item1[i]);
        }
        QName classroom = new QName("classroom");
        toXmlGenerator.startWrappedValue(classroom, student);
        toXmlGenerator.writeNumberField("grade", 4);
        toXmlGenerator.writeNumberField("id", 1);
        toXmlGenerator.writeStringField("name", "软件工程");
        toXmlGenerator.finishWrappedValue(classroom, student);

        toXmlGenerator.writeEndObject();    // 写入对象结束
        // 第三步: 输出前需要flush(),再执行 close() 才会输出到应该序列化的地方

        toXmlGenerator.flush();
        toXmlGenerator.close();


        // FromXmlParser 的实例读取XML反序列化
        FromXmlParser fromXmlParser = (FromXmlParser) xmlMapper.getFactory().createParser(new File("student3.xml"));
    }

输出 student3.xml

<student>
  <cdata><![CDATA[]]">></cdata>
  <age>22</age>
  <id>101</id>
  <name>张三</name>
  <item>1</item>
  <item>2</item>
  <classroom>
    <grade>4</grade>
    <id>1</id>
    <name>软件工程</name>
  </classroom>
</student>