【问题标题】:IndexOutOfBoundsException when processing empty CDATA with Transformer使用 Transformer 处理空 CDATA 时出现 IndexOutOfBoundsException
【发布时间】:2015-03-17 16:01:35
【问题描述】:

我想从一个大型 XML 文件中提取特定节点。效果很好,直到出现没有任何内容的野生 CDATA。

输出:

ERROR:  ''
javax.xml.transform.TransformerException: java.lang.IndexOutOfBoundsException
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:732)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:336)
    at xml_test.XML_Test.extractXML2(XML_Test.java:698)
    at xml_test.XML_Test.main(XML_Test.java:811)
Caused by: java.lang.IndexOutOfBoundsException
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.getTextCharacters(XMLStreamReaderImpl.java:1143)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.handleCharacters(StAXStream2SAX.java:261)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.bridge(StAXStream2SAX.java:171)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.parse(StAXStream2SAX.java:120)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:674)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:723)
    ... 3 more
---------
java.lang.IndexOutOfBoundsException
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.getTextCharacters(XMLStreamReaderImpl.java:1143)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.handleCharacters(StAXStream2SAX.java:261)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.bridge(StAXStream2SAX.java:171)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.parse(StAXStream2SAX.java:120)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:674)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:723)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:336)
    at xml_test.XML_Test.extractXML2(XML_Test.java:698)
    at xml_test.XML_Test.main(XML_Test.java:811)

代码:

InputStream stream = new FileInputStream("C:\\myFile.xml");
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(stream);

TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();

String extractPath = "/root";
String path = "";

while(reader.hasNext()) {
    reader.next();

    if(reader.isStartElement()) {
        path += "/" + reader.getLocalName();

        if(path.equals(extractPath)) {
            StringWriter writer = new StringWriter();
            StAXSource src = new StAXSource(reader);
            StreamResult res = new StreamResult(writer);
            t.transform(src, res); // Exception thrown

            System.out.println(writer.toString());

            path = path.substring(0, path.lastIndexOf("/"));
        }
    }
    else if(reader.isEndElement()) {
        path = path.substring(0, path.lastIndexOf("/"));
    }
}

引发错误的 XML:

<foo><![CDATA[]]></foo>

我可以让Transformer 忽略它吗?或者另一个实现会是什么样子?我无法更改输入 XML!

【问题讨论】:

标签: java xml stax


【解决方案1】:

这是 Xerces 实现的问题,请检查: https://issues.apache.org/jira/browse/XERCESJ-1033

空的 CDATA 似乎不应该存在,所以我能给你的唯一建议是:

  1. 更改 XML 解析器实现
  2. 从源文件中删除空 CDATA(将“&lt;![CDATA[]]&gt;”替换为“”)
    或在 CDATA 中放置一个空格,例如&lt;![CDATA[ ]]&gt;

我添加了一些其他实现的示例。

贾克斯

在 Jaxb 中,您以一种简单的方式将 XML 映射到 POJO。

例如,如果您在 c:\myFile.xml 中有下一个 xml 文件:

<root>
  <foo><![CDATA[]]></foo>
  <foo><![CDATA[some data here]]></foo>
</root>

你可以拥有下一个 POJO:

@XmlRootElement
public class Root {

  @XmlElement(name="foo")
  privateList<Foo> foo;

  public List<Foo> getFooList() {
    return foo;
  }

  public void setFooList(List<Foo> fooList) {
    this.foo = fooList;
  }

}

@XmlType(name = "foo")
public class Foo {

  @XmlValue
  private String content;

  @Override
  public String toString() {
    return content;
  }

}

然后用下一个sn-p从XML解析到Object:

    public static void main(String[] args) {
    try {

        File file = new File("C:\\myFile.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);

        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        Root root = (Root) jaxbUnmarshaller.unmarshal(file);

        for (Foo foo : root.getFooList()) {
            System.out.println(String.format("Foo content: |%s|", foo));
        }

    } catch (JAXBException e) {
        e.printStackTrace();
    }

}

我对此进行了测试,没有出现错误。

【讨论】:

  • 然后需要另一个实现。你有什么建议吗? @Ron 在this 评论中说,我们可以不使用Transformer 直接管道XML。效果如何?
  • @halloei 这取决于您要查找的内容。 XMLBeans 非常灵活,让您可以使用 getter/setter,遍历 XML 甚至 DOM 或 XPath。如果你想将 XML 映射到 POJO 的尝试 Jaxb。
  • 到目前为止非常感谢。我会试试你的建议。我得到了我的原始代码,但在某种程度上我不想离开它。您可能对此感兴趣:stackoverflow.com/questions/28151710/…
【解决方案2】:

我在同一应用程序的两个构建中遇到此错误,一个构建在处理空 &lt;![CDATA[]]&gt; 时出现错误,另一个则没有。

不同之处在于损坏的构建使用了 Xerces(嵌入在 jre 中),而工作构建在类路径上添加了额外的依赖项 https://mvnrepository.com/artifact/org.codehaus.woodstox/woodstox-core-asl

损坏构建的堆栈跟踪的相关部分将是

java.lang.Exception
        at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.getTextCharacters(XMLStreamReaderImpl.java:1144)
        at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.handleCharacters(StAXStream2SAX.java:242)
        at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.bridge(StAXStream2SAX.java:152)
        at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.parse(StAXStream2SAX.java:101)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:679)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:728)
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:343)
        at com.sun.org.apache.xerces.internal.jaxp.validation.StAXValidatorHelper.validate(StAXValidatorHelper.java:107)
        at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:123)
        at javax.xml.validation.Validator.validate(Validator.java:124)

在工作构建期间

java.lang.Exception
    at com.ctc.wstx.sr.BasicStreamReader.getTextCharacters(BasicStreamReader.java:894)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.handleCharacters(StAXStream2SAX.java:242)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.bridge(StAXStream2SAX.java:152)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.parse(StAXStream2SAX.java:101)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:679)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:728)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:343)
    at com.sun.org.apache.xerces.internal.jaxp.validation.StAXValidatorHelper.validate(StAXValidatorHelper.java:107)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:123)
    at javax.xml.validation.Validator.validate(Validator.java:124)

这个 Q/A 帮助我对 Woodstox What is the relation between fasterxml(jackson-dataformat-xml) and Woodstox? 感到“舒服”。

【讨论】:

  • 你是我的英雄,非常感谢这个建议。我的项目在很大程度上依赖于 Transformer,所以我不能只迁移到 jaxb。感谢您的建议,我唯一需要做的就是添加这个 woodstox-core-asl 作为依赖项,它可以工作,不需要其他更改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 2023-03-11
  • 1970-01-01
  • 2018-10-07
  • 2017-12-05
  • 1970-01-01
  • 2014-06-10
相关资源
最近更新 更多