【问题标题】:Stax event reader skipping white spaceStax 事件阅读器跳过空白
【发布时间】:2016-11-20 15:27:29
【问题描述】:

我正在编写一个实用程序来更改 XML 文件中的文本实体,使用 STAX 事件模型。我发现源文档中的一些空白没有被复制到输出中。我写了这个示例程序:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

import javax.xml.stream.*;
import javax.xml.stream.events.*;

public class EventCopy {
    private static final String INPUT =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<foo><bar>baz</bar></foo>\n";

    public static void main(String[] args) throws XMLStreamException, IOException {
        InputStream reader = new ByteArrayInputStream(INPUT.getBytes(StandardCharsets.UTF_8));
        OutputStream writer = new ByteArrayOutputStream();

        XMLInputFactory input = XMLInputFactory.newInstance();
        XMLEventReader xmlReader = input.createXMLEventReader(reader, "UTF-8");
        try {
            XMLOutputFactory output = XMLOutputFactory.newInstance();
            XMLEventWriter xmlWriter = output.createXMLEventWriter(writer, "UTF-8");
            try {
                while (xmlReader.hasNext()) {
                    XMLEvent event = xmlReader.nextEvent();
                    System.out.print(event.getEventType() + ",");
                    xmlWriter.add(event);
                }
            } finally {
                xmlWriter.close();
            }
        } finally {
            xmlReader.close();
        }
        System.out.println("\n[" + writer.toString() + "]");
    }
}

使用 Oracle Java 7 附带的默认 Stax 实现,输出:

7,1,1,4,2,2,8,
[<?xml version="1.0" encoding="UTF-8"?><foo><bar>baz</bar></foo>]

XML 序言后面和输入末尾的换行符已消失。似乎读者甚至没有为他们生成事件。

我认为可能是 XML 阅读器将输入流留在了最后一个 XML 标记的末尾,并尝试添加代码以将尾随字符从输入复制到输出:

    ...
    } finally {
        xmlReader.close();
    }
    int ii;
    while (-1 != (ii = reader.read())) {
        writer.write(ii);
    }

但这没有任何作用。

有没有办法让 STAX 更忠实地复制这个 XML?不同的 STAX 实现在这里会有不同的表现吗?

【问题讨论】:

  • 尝试使用“
    ”而不是“\n”

标签: java xml stax


【解决方案1】:

参考:XML spec

格式良好的 XML 文档遵循规范语法:

[1]  document ::= prolog element Misc*
[22] prolog   ::= XMLDecl? Misc* (doctypedecl Misc*)?
[23] XMLDecl  ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
[27] Misc     ::= Comment | PI | S
[3]  S        ::=   (#x20 | #x9 | #xD | #xA)+

[39] element  ::= EmptyElemTag
                  | STag content ETag
[40] STag     ::= '<' Name (S Attribute)* S? '>'
[43] content  ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)*
[14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
[42] ETag     ::= '</' Name S? '>'

XMLDecl 和根元素之间的换行符,以及根元素之后的换行符,只是 S,解析器允许自己忽略。

让我举一个不同的空白的例子。假设您有一个稍微不同的 XML:

private static final String INPUT =
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
        "<foo>\n<bar>baz</bar></foo>\n";

&lt;foo&gt;&lt;bar&gt; 之间的换行符是 CharData。请注意,StAX 会为该角色正确生成事件。

如果您真的想保留S,那么您需要将INPUT 读取为文本而不是XML 文档。请注意,两个 XML 文档实例,一个带有这两个特定的 S 字符,一个没有它们,是等效的。

【讨论】:

  • 我认为输出在语义上等同于输入。这不是我真正想要的。我担心如果这个 XML 过滤器对 XML 进行了不必要的更改,我的用户会抱怨,我宁愿不必与他们争论这些更改无关紧要。
  • @Kenster 我猜你缺少选择。然后将 XML 读取为文本。我相信大多数 XML 解析器都会忽略那些空格
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 2011-12-13
  • 2013-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多