Stax事件阅读器跳过空白区域

时间:2016-11-20 15:27:30

标签: java xml stax

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

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实现会有不同的表现吗?

1 个答案:

答案 0 :(得分: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";

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

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