读取XML文件会返回错误的字符

时间:2013-03-20 12:47:59

标签: java xml readfile

我有一个包含数千个标签的XML文件来阅读其文本内容,如下面的屏幕截图所示:

XML file to read

我正在尝试使用以下代码阅读所有“word”标签的文本内容:

String filePath = "...";
File xmlFile = new File( filePath );

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document domObject = db.parse( xmlFile );
domObject.getDocumentElement().normalize();
NodeList categoryNodes = domObject.getElementsByTagName( "category" );   // Get all the <category> nodes.

for (int s = 0; s < categoryNodes.getLength(); s++) {    //Loop on the <category> nodes.
    String categoryName = categoryNodes.item(s).getAttributes().getNamedItem( "name" ).getNodeValue(); 

    if( selectedCategoryName.equals( categoryName ) ) {  //get its words.
        NodeList wordsNodes = categoryNodes.item(s).getChildNodes();

        for( int i = 0; i < wordsNodes.getLength(); i++ ) {
            if( wordsNodes.item( i ).getNodeType() != Node.ELEMENT_NODE ) continue;
            String word = wordsNodes.item( i ).getTextContent();
            categoryWordsList.add( word );  // Some words are read wrong !!
        }

        break;
    }
}

但由于某些原因,许多单词的读法都是错误的,例如:

"AMK6780KBU" is read as "9826</word"

"ASSI.ABR30326" is read as "rd>ASSI.AEP26"

"ASSI.25066" is read as "SI.4268</6"

可能是因为文件大小很大。如果我只是添加一些空行或从XML文件中删除一些空行,其他单词将被读错,而不是上面提到的那些,这是一件奇怪的事情!

您可以从here下载XML文件。

2 个答案:

答案 0 :(得分:3)

<强>解决方案

见下文: - )

我在此过程中尝试了什么

1.1 -> 1.0更改XML版本为我解决了问题。我正在使用Java 1.6.0_33(正如@orique在评论中指出的那样)。

在我的测试中,在一定数量的节点之后肯定存在腐败问题。我把它缩小到ASSI.MTK69609左右的某个地方。删除所有内容,包括该行修复了前一个词的损坏。

只需将声明更改为:

即可解决损坏问题
<?xml version="1.0">

我看到使用整个原始源XML的零损坏。

同样,如果您将版本保留在1.1但从源中删除空白节点,结果将按预期进行,例如:

    <word>ASSI.MTK68490</word>
    <word>ASSI.MTK6862617</word>
<word>ASSI.MTK693115</word>
<word>ASSI.MTK69609</word>

产生所需的输出和

    <word>ASSI.MTK68490</word>
    <word>ASSI.MTK6862617</word>
    <word>ASSI.MTK693115</word>
    <word>ASSI.MTK69609</word>

已损坏。

删除某些行尾“节点”也纠正了问题,例如

    <word>ASSI.MTK693115</word><word>ASSI.MTK69609</word>

所以这一切都指向一个错误,但在哪里......?最终它点击了!的的Xerces

Java 1.6(可能是1.7)附带的Xerces版本是旧的,旧的,旧的和错误的(例如#6760982)。事实上,我可以通过简单地添加:

来打破我的测试类
Document domObject = db.parse( xmlFile );
domObject.normalizeDocument(); // <-- causes following Exception

Exception in thread "main" java.lang.NullPointerException
    at com.sun.org.apache.xerces.internal.util.XML11Char.isXML11ValidNCName(XML11Char.java:340)

已经有many defects fixed for XML 1.1,所以在预感中我下载了最新版本Xerces2 Java 2.11.0

只需使用最新版本运行就会产生预期的未损坏输出。

java -classpath .;xercesImpl.jar;xml-apis.jar Foo > foo.txt

答案 1 :(得分:1)

我们注意到getTextContent()在某些Windows实现上存在错误。

我们的解决方法是做这样的事情

            // getTextContent is buggy on some Java Windows Implementations
            if ( n.getNodeType(  ) == Node.ELEMENT_NODE ) {

                results [ i ] = (String) xPathFunction.evaluate( "./text()", n, XPathConstants.STRING );
            } else {  //Node.TEXT_NODE

                results [ i ] = n.getNodeValue(  );
            }

xPathFunctionjavax.xml.xpath.XPath。价格昂贵,但工作可靠。

实际上在你的情况下我会直接使用XPath并调用类似的东西,

NodeList l = (NodeList) xPathFunction.evaluate( "/categories/category/word/text()", domObject, XPathConstants.NODESET )

修改

打败我!在OSX,Java 1.6.0_43上,我得到了相同的行为。如果有任何疑问,DOM模型在Java中是错误的...错误的值似乎可靠地出现在某些时间间隔,这看起来像一些字节缓冲区溢出。我从未收到过OOM错误。

以下是我尝试失败的原因:

  • word.getFirstChild().getNodeValue();代替word.getTextContent(); - &gt;没有改变行为
  • 使用InputSource作为DocumentBuilder的输入,而非使用File
  • 运行XPath(“/ categories / category [@ name ='Category1'] / word / text()”)而不是循环遍历节点并手动遍历他们的孩子
  • 使用Saxon作为XPath引擎运行相同的测试
  • 检查XML文件中的“奇怪”字符

我相信DocumentBuilder是罪魁祸首。这是记忆界的痛苦。

您的下一个最佳机会是使用SAX Parser或任何其他流解析器。由于您的数据模型很小且非常简单,因此实现起来应该很简单。为了进一步简化实施,您可以尝试XMLDog。我们使用略微修改的版本来成功解析千兆字节大小的XML文件。

如果您发现此问题,请更新此帖。