在Java中解析XML的问题

问题描述:

解析XML文档时遇到了一些麻烦。出于某种原因,有文本节点,我不希望他们是,因此我的测试变成红色。该XML文件是这样的:在Java中解析XML的问题

<?xml version="1.0" encoding="UTF-8"?> 
<RootNode> 
    <PR1>PR1</PR1> 
    <ROL>one</ROL> 
    <ROL>two</ROL> 
    <DG1>DG1</DG1> 
    <ROL>three</ROL> 
    <ZBK>ZBK</ZBK> 
    <ROL>four</ROL> 
</RootNode> 

现在我有此代码段可以重现错误:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document doc = builder.parse(TestHL7Helper.class.getResourceAsStream("TestHL7HelperInput.xml")); 
Node root = doc.getFirstChild(); 
Node pr1 = root.getFirstChild(); 

检查根可变产量[RootNode: null]这似乎是正确的,但后来不知何故全错了。 pr1变量原来是一个文本节点[#text:\n ] - 但为什么解析器认为新行和空格是文本节点?这不应该被忽略吗?我试图改变编码,但也没有帮助。有关于此的任何想法?

如果我删除所有的新线条和空间,并有我的XML文档中只有一行这一切工作正常...

+0

这里是一个[DOM分析样品] [1] 也许这会帮助你。 [1]:http://stackoverflow.com/a/7902162/529543 – 2013-04-26 08:21:10

+0

也许问题标题应该改变。我仔细研究了一下关于混合内容和DOM解析的一些信息,并在那里得到了答案,但问题标题乍一看并没有吸引我。就像“使用Java DOM解析带有混合内容的XML的问题”。 – dodecaplex 2016-10-25 06:52:34

您可以通过检查节点的类型解决这一普遍问题:

if (someNode instanceof Element) { 
    // ... 
} 

这可以容易地形成一个环的一部分,如:

NodeList childNodes = root.getChildNodes(); 
for (int i = 0; i < childNodes.getLength(); i++) { 
    if (childNodes.item(i).getNodeType() == Node.ELEMENT) { 
    Element childElement = (Element) childNodes.item(i); 
    // ... 
    } 
} 

可替代地,使用类似XMLBeans以减少引入的错误时的人的可能性ually解析XML。获得一个经过充分测试的图书馆来为您完成这项工作!

+0

这是我想过的解决方案,但它有点难看。必须有一些东西不会用我所有的if和else来填充我的代码,只是为了检查解析是否有问题。 – Viciouss 2013-04-26 08:24:00

+0

@Viciouss [Sirko的解决方案](http://stackoverflow.com/a/16231783/474189)更直接,如果你有独特的名字。或者,您可以考虑使用类似[XMLBeans](http://xmlbeans.apache.org/documentation/tutorial_getstarted.html)的类来生成专门用于读取与XSD/DTD匹配的XML文件的类。 – 2013-04-26 08:28:13

+0

我同意@Duncan - 使用现有的库来处理您的解析。我过去使用过JDOM,并且发现它简单直观,没有太多的学习曲线 – DaveH 2013-04-26 08:35:21

实际上,其他节点之间的所有文本本身形成一个文本节点。因此,如果您使用getFirstChild(),您还将检索这些文本节点。

在你的情况下,所有的非文本子节点有一个独特的名字,所以你可以通过使用getElementsByTagName()单独让他们:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document doc = builder.parse(TestHL7Helper.class.getResourceAsStream("TestHL7HelperInput.xml")); 
Node root = doc.getFirstChild(); 
Node pr1 = (root.getElementsByTagName("PR1"))[0]; 

一般来说,我不会依赖XML文档中的位置,但在标签名称,属性或ID等东西。

+0

我需要依靠这个,因为我必须在其中一个测试中检查兄弟姐妹。例如,我用getElementsByTagName获取PR1节点,然后我想检查有多少ROL节点落后。对于这个任务,我需要使用getNextSibling(),它似乎有完全相同的问题。 – Viciouss 2013-04-26 08:27:43

+0

@Viciouss也许这个问题将帮助你然后:http://stackoverflow.com/q/978810/1169798 – Sirko 2013-04-26 08:31:49

+0

我想我会做的只是相反的方式。我将使用xpath来选择与特定名称匹配的兄弟。其他方法似乎并不令人满意。 – Viciouss 2013-04-26 08:40:40

XML支持混合内容,意思是元素可以同时具有文本元素和元素子节点。这是为了支持使用情况如下所示:

<text>I've bolded the <b>important</b> part.</text> 

的input.xml

这意味着,在默认情况下DOM解析器将把空白节点下面的文档作为显著的(下面是一个简化XML文档的版本):

<RootNode> 
    <PR1>PR1</PR1> 
</RootNode> 

演示代码

如果您有XML架构,则可以在DocumentBuilderFactory上设置ignoringElementContentWhitespace属性,因为那样DOM解析器将知道空白是否以及何时有意义。

import java.io.File; 
import javax.xml.XMLConstants; 
import javax.xml.parsers.*; 
import javax.xml.validation.*; 

import org.w3c.dom.Document; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
     Schema s = sf.newSchema(new File("src/forum16231687/schema.xsd")); 

     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     dbf.setSchema(s); 
     dbf.setIgnoringElementContentWhitespace(true); 

     DocumentBuilder db = dbf.newDocumentBuilder(); 
     Document d = db.parse(new File("src/forum16231687/input.xml")); 
     System.out.println(d.getDocumentElement().getChildNodes().getLength()); 
    } 

} 

模式。xsd

如果您创建schema.xsd,如下所示,那么演示代码将报告根元素有1个子节点。

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema"> 
    <element name="RootNode"> 
     <complexType> 
      <sequence> 
       <element name="PR1" type="string"/> 
      </sequence> 
     </complexType> 
    </element> 
</schema> 

如果更改schema.xsd使得RootNode具有混合内容的演示代码将报告RootNode有3个节点。

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema"> 
    <element name="RootNode"> 
     <complexType mixed="true"> 
      <sequence> 
       <element name="PR1" type="string"/> 
      </sequence> 
     </complexType> 
    </element> 
</schema>