【问题标题】:Unmarshaling xml with html entities using JAXB使用 JAXB 将 xml 与 html 实体解组
【发布时间】:2009-06-22 21:20:26
【问题描述】:

我需要将维基百科修订历史加载到 POJO 中,因此我使用 JAXB 来解组 wikipeida 数据转储(嗯,它的各个页面)。问题是文本节点偶尔包含未在维基百科 xml 转储中定义的实体。例如:° (`°' 请记住,我不知道我需要能够读取的完整实体集。我的输入文件是 3tb,所以我们假设所有 html 可以呈现的内容都在其中。 )。

如何配置 JAXB 来处理无效 xml 的实体?

这是 JAXB 在遇到未定义实体时抛出的 SAX 异常:

Exception in thread "main" javax.xml.bind.UnmarshalException

 - with linked exception:

[org.xml.sax.SAXParseException: The entity "deg" was referenced, but not declared.]

    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:315)

    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:481)

    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:199)

    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:168)

    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:137)

    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:184)

    at com.stottlerhenke.tools.wikiparse.WikipediaIO.readPage(WikipediaIO.java:73)

    at com.stottlerhenke.tools.wikiparse.WikipediaIO.main(WikipediaIO.java:53)

Caused by: org.xml.sax.SAXParseException: The entity "deg" was referenced, but not declared.

    at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)

    at org.apache.xerces.util.ErrorHandlerWrapper.fatalError(Unknown Source)

    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)

    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)

    at org.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source)

    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEntityReference(Unknown Source)

    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)

    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)

    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)

    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)

    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)

    at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)

    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:195)

编辑:触发该异常的输入是Arctic Circle 上的维基百科文章的完整修订历史记录。用于生成 JAXB 类的 XSD 在这里:http://www.mediawiki.org/xml/export-0.3.xsd

编辑:这个问题的根源是我的一个错误——我使用的初始提取器没有正确维护编码实体。但是,如果有人遇到我认为遇到的问题,我确实找到了解决方法。见下文。

【问题讨论】:

    标签: java xml jaxb


    【解决方案1】:

    解析实体不是 JAXB 的工作。这是底层的工作 XML 解析器。

    你可以做的是:

    • 使用 DOM 自己读取数据
    • 用您希望的东西替换所有未解析的实体
    • 然后,让 JAXB 处理结果

    【讨论】:

    • 由于 Jaxb 从 XML 解析器中抽象出来,我认为它应该提供一些方法来修复需要在解析器级别管理的内容(可能只是通过使用依赖注入来提供不同的解析器)。再一次,我给了 JAXB 无效输入——那我期待什么? ;)
    【解决方案2】:

    这是一个 hack,但它可以在紧要关头工作。

    我从 w3.org 下载了 html 实体定义,并将输入 xml 文件的 doctype 设置为 xhtml-transitional,但将 doctype url 定向到本地 dtd:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "xhtml1-transitional.dtd">
    

    xhtml1-transitional.dtd 反过来要求:

    • xhtml-lat1.ent
    • xhtml-special.ent
    • xhtml-symbol.ent

    我把它吸下来放在旁边的 xhtml1-transitional.dtd

    (所有文件都在:http://www.w3.org/TR/xhtml1/DTD/

    就像我说的,丑得要命,但它确实似乎完成了这项工作。

    【讨论】:

    • 您是否有理由必须将 dtd 文档设为本地?删除 DTD 文档发生了什么?
    • 当 JAXB 尝试直接检索 DTD 时,w3.org 返回了一个错误代码——即使该 url 在浏览器中有效。我推测 w3.org 正在基于用户代理阻止对 dtds/etc 的访问,以阻止人们从 API 访问他们的服务器。 (w3.org 在一年前发布了一个请求,呼吁人们停止编写这样做的应用程序:w3.org/blog/systeam/2008/02/08/w3c_s_excessive_dtd_traffic)我不确定您所说的“删除 DTD 文档发生了什么?”。
    • 您可能希望使用 XML 目录指向本地副本,而不是更改 DOCTYPE 本身。详情请见xml.apache.org/commons/components/resolver/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-31
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    相关资源
    最近更新 更多