java - 解析 XML 并在不绑定(bind)命名空间的情况下获取 DOM 树 - Java

标签 java xml dom xslt sax

我有一个类似 XML 的文件:

<p>something</p>
<ac:image>
    <ri:attachment ri:filename="IMAGE.PNG" />
</ac:image>
<ac:macro ac:name="screenshot">
    <ac:default-parameter>IMAGE.ss</ac:default-parameter>
</ac:macro>
<p>something</p>

我需要用 XSLT 模板转换它 - 我想替换所有 <ac:image><ac:macro ac:name="screenshot"> .通常,解析和转换格式良好且众所周知的 XML 非常容易。我的情况完全不同。

如您所见,它没有根元素和 XML 序言。但这不是问题,我可以添加 <?xml version="1.0"?>并用任意元素包装内容,例如 <root>避免异常:

Caused by: org.jdom.input.JDOMParseException: Error on line 1: Content is not allowed in prolog.

示例 XML 包含三个命名空间 - 默认、acri .由于代码将在客户指定的内容上运行,因此可能还有一些我不知道的其他 namespace 。我无法在解析 XML 之前绑定(bind)所有命名空间,所以我遇到了一个异常:

Caused by: org.xml.sax.SAXParseException: Content is not allowed in prolog.

我在 Internet 的某处发现 SAX 解析器能够在不解析 namespace 的模式下解析 XML。在默认模式下,您会得到 namespace=acelement=macro ,而在非命名空间模式下,您没有命名空间和 element=ac:macro .这是需要的。您只需要在解析器上设置 SAX 功能:namespaces=false , namespace-prefixes=true .

final XMLReader sax = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
sax.setFeature("http://xml.org/sax/features/validation", false);
sax.setFeature("http://xml.org/sax/features/namespaces", false);
sax.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
sax.parse(new InputSource(new StringReader(content))); // parse returns void

它没有抛出任何异常,所以看起来 XML 被解析没有错误。但是,我需要一个 DOM 树,以便我可以使用 XSLT 对其进行转换。那么让我们使用 JDOM:

// all classes are org.jdom.*
final SAXBuilder sax = new SAXBuilder(false); // validate=false
sax.setFeature("http://xml.org/sax/features/namespaces", false);
sax.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
final Document document = sax.build(new StringInputStream(content));

不幸的是,我遇到了一个异常(exception):

Caused by: org.jdom.IllegalNameException: The name "" is not legal for JDOM/XML elements: XML names cannot be null or empty.
    at org.jdom.Element.setName(Element.java:206)
    at org.jdom.Element.<init>(Element.java:140)
    at org.jdom.Element.<init>(Element.java:152)
    at org.jdom.DefaultJDOMFactory.element(DefaultJDOMFactory.java:138)
    at org.jdom.input.SAXHandler.startElement(SAXHandler.java:511)
    at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
    at org.apache.xerces.impl.dtd.XMLDTDValidator.startElement(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentScannerImpl$ContentDispatcher.scanRootElementHook(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 org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:453)
    at org.jdom.input.SAXBuilder.build(SAXBuilder.java:770)
    at com.screensnipe.confluence.macro.XhtmlImageMacroReplacer.replaceImageMacroInText(XhtmlImageMacroReplacer.java:118)

JDOM 提示非法标签名称 <> .我当然没有这样的。看起来 JDOM 在 SAXHandler.java:511, element = factory.element(localName); 中有一个错误应该是 element = factory.element(qName); .

我也试过 XOM。 XOM does not work with "namespaces" feature set to false .

我还尝试了 TagSoup 库。我不喜欢它,因为它弄乱了输出 XML。添加 XML prolog 和根元素不是问题。弄乱 namespace 是。

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
    <body>
        <p>something</p>
        <ac:image xmlns:ac="urn:x-prefix:ac"> <!-- :( -->
             <ri:attachment xmlns:ri="urn:x-prefix:ri" ri:filename="IMAGE.PNG" />
        </ac:image>
        ...

问题是:如何从我的 XML 中获取 DOM 树? (Java) 无需编写我的 JDOM 版本。我将不胜感激一个可行的解决方案。只需解析并获取 DOM 树。命名空间不会像 TagSoup 库那样被破坏的树。

或更多以目标为中心的问题:如何替换 <ac:image><ac:macro ac:name="screenshot">不接触其他标签? (Java) 所有其他标签、命名空间或其他任何东西都应该不受影响。 (不要建议任何正则表达式)

最佳答案

如果您愿意进行预处理,例如添加周围的根元素,您还可以查看 XML 文件中的命名空间前缀,并将它们中的每一个的虚拟声明添加到您要添加的根元素中.

那么您将不需要可以告诉您不要解析 namespace 前缀的解析器。

关于java - 解析 XML 并在不绑定(bind)命名空间的情况下获取 DOM 树 - Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7337275/

相关文章:

java - 数组:个人号码 (CPR)

javascript - 在 IE 中使用 JavaScript 将 XML 加载到 DIV 时出现问题

xml - 使用 xml 文件的文件夹作为 nhibernate 的数据源

javascript - 删除节点同时保留所有子节点和选择

Javascript 通过 div 中的元素递增?

java - Spring控制台应用程序,从JAR外部加载属性文件

Java-->CreateProcess error=2,系统找不到指定的文件

php - XML 使 PHP 出现意外的字符串错误

Javascript 集中控制

java - 使用 POST 方法从 URL 中提取参数