【问题标题】:Java - Read XML and leave all entities aloneJava - 读取 XML 并保留所有实体
【发布时间】:2011-11-15 04:49:29
【问题描述】:

我想使用 SAX 或 StAX 读取 XHTML 文件,无论哪种效果最好。 但我不希望实体被解决、替换或类似的事情。 理想情况下,它们应该保持原样。 我不想使用 DTD。

这是一个(可执行,使用 Scala 2.8.x)示例:

import javax.xml.stream._
import javax.xml.stream.events._
import java.io._

println("StAX Test - "+args(0)+"\n")
val factory = XMLInputFactory.newInstance
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false)
factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false)

println("------")
val xer = factory.createXMLEventReader(new FileReader(args(0)))
val entities = new collection.mutable.ArrayBuffer[String]
while (xer.hasNext) {
    val event = xer.nextEvent
    if (event.isCharacters) {
        print(event.asCharacters.getData)
    } else if (event.getEventType == XMLStreamConstants.ENTITY_REFERENCE) {
        entities += event.asInstanceOf[EntityReference].getName
    }
}
println("------")
println("Entities: " + entities.mkString(", "))

鉴于以下 xhtml 文件...

<html>
    <head>
        <title>StAX Test</title>
    </head>
    <body>
        <h1>Hallo StAX</h1>
        <p id="html">
            &lt;div class=&quot;header&quot;&gt;
        </p>
        <p id="stuff">
            &Uuml;berdies sollte das hier auch als Copyright sichtbar sein: &#169;
        </p>
        Das war's!
    </body>
</html>

...运行scala stax-test.scala stax-test.xhtml 将导致:

StAX Test - stax-test.xhtml

------


    StAX Test


    Hallo StAX

      <div class="header">


      berdies sollte das hier auch als Copyright sichtbar sein: ?

    Das war's!

------
Entities: Uuml

所以所有实体都或多或少地被成功替换了。 不过,我所期望的和我想要的是这样的:

StAX Test - stax-test.xhtml

------


    StAX Test


    Hallo StAX

      &lt;div class=&quot;header&quot;&gt;


      &Uuml;berdies sollte das hier auch als Copyright sichtbar sein: &#169;

    Das war's!

------
Entities: // well, or no entities above and instead:
// Entities: lt, quot, quot, gt, Uuml, #169

这甚至可能吗? 我想解析 XHTML,进行一些修改,然后再次将其输出为 XHTML。所以我真的希望实体保留在结果中。

另外我不明白为什么 Uuml 被报告为 EntityReference 事件,而其余的则没有。

【问题讨论】:

    标签: java xml sax entities stax


    【解决方案1】:

    一些术语:&amp;#x169; 是数字字符引用(不是实体),&amp;#auml; 是实体引用(不是实体)。

    我认为任何 XML 解析器都不会报告对应用程序的数字字符引用——它们总是会被扩展。实际上,您的应用程序不应该关心这一点,就像它关心属性之间有多少空白一样。

    对于实体引用,SAX 等低级解析接口将报告实体引用的存在——无论如何,它会在它们出现在元素内容中时报告它们,而不是在属性内容中。有些特殊事件只通知 LexicalHandler 而不是 ContentHandler。

    【讨论】:

      【解决方案2】:

      “为什么 Uuml 被报告为 EntityReference 事件而其余的不是”的答案是其余部分由 XML 规范定义,而 &amp;Uuml; 特定于 HTML 4.0

      由于您的目标是编写修改后的 XHTML,可能通过将“编码”设置为“US-ASCII”和/或“方法”来强制序列化程序发出数字实体引用" 到 "html"。 XSLT spec(Java XML 序列化程序的基础)表示,当方法是 html 时,序列化程序“可能使用字符实体引用输出字符”。如果不支持命名实体,将编码设置为 ASCII 可能会强制它使用数字实体。

      【讨论】:

        【解决方案3】:

        在 Java 中,我会使用正则表达式。

        public static void main(String... args) throws IOException {
          BufferedReader buf = new BufferedReader(new FileReader(args[0]));
          Pattern entity = Pattern.compile("&([^;]+);");
          Set<String> entities = new LinkedHashSet<String>();
          for (String line; (line = buf.readLine()) != null; ) {
            Matcher m = entity.matcher(line);
            while (m.find())
              entities.add(m.group(1));
          }
          buf.close();
          System.out.println("Entities: " + entities);
        }
        

        打印

        Entities: [lt, quot, gt, Uuml, #169]
        

        【讨论】:

        • 和几乎所有尝试使用正则表达式解析 XML 的人一样,你会错的。例如,您的正则表达式将拾取出现在 cmets 和 CDATA 部分中的类似实体的内容;如果评论包含一个没有分号的&符号,它将造成严重破坏。永远不要使用正则表达式来解析 XML - 你总是会出错。投反对票。
        • @Michael Kay,这很好地解释了为什么它可能很糟糕。我怀疑您遇到的 XML 比我遇到的更多。我看到的 XML 通常是为某种目的而设计的。
        猜你喜欢
        • 2022-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-26
        • 2017-06-05
        • 1970-01-01
        • 2023-03-29
        • 2014-01-13
        相关资源
        最近更新 更多