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

Java 读取XML文件返回错误的字符,java,xml,readfile,Java,Xml,Readfile,我有一个包含数千个标记的XML文件,可以读取它们的文本内容,如下面的屏幕截图所示: 我正在尝试使用以下代码读取所有“word”标记的文本内容: String filePath = "..."; File xmlFile = new File( filePath ); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder();

我有一个包含数千个标记的XML文件,可以读取它们的文本内容,如下面的屏幕截图所示:

我正在尝试使用以下代码读取所有“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;
    }
}
String filePath=“…”;
文件xmlFile=新文件(文件路径);
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
文档domObject=db.parse(xmlFile);
domObject.getDocumentElement().normalize();
NodeList categoryNodes=domObject.getElementsByTagName(“类别”);//获取所有节点。
对于节点上的(int s=0;s
但由于某些原因,许多单词被误读,例如:

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

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

"ASSI.25066" is read as "SI.4268</6"
“AMK6780KBU”读作“9826ASSI.AEP26”

“ASSI.25066”被理解为“SI.4268我们注意到
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(  );
            }
xPathFunction
是一个
javax.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();
    ->行为没有变化
  • 使用
    InputSource
    作为
    DocumentBuilder
    的输入,而不是使用
    文件
  • 运行
    XPath
    (“/categories/category[@name='Category1']/word/text()”),而不是在节点上循环并手动遍历其子节点
  • 使用Saxon作为XPath引擎运行相同的测试
  • 检查XML文件中的“奇怪”字符
我相信
DocumentBuilder
是罪魁祸首。它是一个内存消耗者

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


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

解决方案

见下文:-)

我在这个过程中尝试了什么

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

在我的测试中,一定数量的节点后肯定会出现损坏问题。我将其缩小到
ASSI.MTK69609
附近。删除所有内容,包括该行,修复了前面单词的损坏

通过简单地将声明更改为:

<?xml version="1.0">
产生所需的输出和输出

    <word>ASSI.MTK68490</word>
    <word>ASSI.MTK6862617</word>
    <word>ASSI.MTK693115</word>
    <word>ASSI.MTK69609</word>
有一种预感,我下载了最新版本的Xerces2 Java 2.11.0

只需使用最新版本运行即可获得预期的未损坏输出

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

Header说文件是UTF-8格式的,是真的吗?是的,有问题吗?我用Firefox打开了XML,它抱怨XML声明格式不好。它抱怨
1.1
版本。也许你的解析器对1.1 XML文件也有一些问题?还有,我用新的过去更新了帖子ebin链接,这里是XML链接:适用于jdk 1.7和windows 7上的捆绑xerces。您尝试过使用最新版本吗?谢谢。您能告诉我有关此解决方案的更多详细信息吗?我真的不明白!使用
xPathFactory=xPathFactory.newInstance();XPath XPath xPathFunction=xPathFactory.newXPath()获取
XPath
然后运行上面的
评估
;或者简单地将
wordsNodes.item(i).getTextContent()替换为
wordsNodes.item(i).getNodeValue();
在代码中;如果
wordNodes
都是
Node.TEXT\u Node
否,getNodeValue()类型,那么它可能会起作用始终为我返回null。我的所有节点的类型都是Node.ELEMENT\u Node。然后,您需要获取此ELEMENT\u节点中的文本节点并调用getNodeValue或如上所述使用xPath调用
(String)xPathFunction。求值(“./Text()”,n,XPathConstants.String);
。老实说,您应该使用XPath解决方案,您将在一行调用中替换嵌套的循环和ifs,然后是一个简单的循环,使代码看起来更可读。我使用了:String word=wordsNodes.item(I).getFirstChild().getNodeValue();…结果完全一样!太好了。感谢您为此付出的努力。我检查了为什么我们没有这个问题:我们在认可的libs中有一个最新版本的xercesImpl.jar…andyb..当我再次尝试将版本更改为1.0时,我发现它正在工作。我向“orique”道歉“为了这个。我第一次测试这个的时候好像做错了什么。根据你的解释
    <word>ASSI.MTK693115</word><word>ASSI.MTK69609</word>
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)
java -classpath .;xercesImpl.jar;xml-apis.jar Foo > foo.txt