Stax 事件 reader 跳过白色 space

Stax event reader skipping white space

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

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 序言之后和输入末尾的换行符已消失。似乎 reader 甚至没有为他们生成事件。

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

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

但这没有任何效果。

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

参考: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解析器允许自己忽略的。

让我举一个不同的白色的例子space。假设你有一个稍微不同的 XML:

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

<foo><bar> 之间的换行是 CharData。请注意,StAX 会为此角色正确生成一个事件。

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