使用 Java DOM 获取 XML 节点文本值

Posted

技术标签:

【中文标题】使用 Java DOM 获取 XML 节点文本值【英文标题】:Getting XML Node text value with Java DOM 【发布时间】:2010-10-20 20:32:49 【问题描述】:

我无法使用Node.getNodeValue()Node.getFirstChild().getNodeValue()Node.getTextContent() 获取文本值。

我的 XML 是这样的

<add job="351">
    <tag>foobar</tag>
    <tag>foobar2</tag>
</add>

我正在尝试获取 tag 值(非文本元素提取工作正常)。我的 Java 代码听起来像

Document doc = db.parse(new File(args[0]));
Node n = doc.getFirstChild();
NodeList nl = n.getChildNodes();   
Node an,an2;

for (int i=0; i < nl.getLength(); i++) 
    an = nl.item(i);

    if(an.getNodeType()==Node.ELEMENT_NODE) 
        NodeList nl2 = an.getChildNodes();

        for(int i2=0; i2<nl2.getLength(); i2++) 
            an2 = nl2.item(i2);

            // DEBUG PRINTS
            System.out.println(an2.getNodeName() + ": type (" + an2.getNodeType() + "):");

            if(an2.hasChildNodes())
                System.out.println(an2.getFirstChild().getTextContent());

            if(an2.hasChildNodes())
                System.out.println(an2.getFirstChild().getNodeValue());

            System.out.println(an2.getTextContent());
            System.out.println(an2.getNodeValue());
        
    

打印出来

tag type (1): 
tag1
tag1
tag1
null
#text type (3):
_blank line_
_blank line_
...

感谢您的帮助。

【问题讨论】:

如果您清楚地指出变量 'n' 当前准确地持有什么,Document 或 documentElement 会有所帮助? 我添加了'n'声明部分 【参考方案1】:

我也会打印出an2.getNodeName() 的结果以用于调试目的。我的猜测是你的树爬取代码没有爬到你认为的节点。缺少检查代码中的节点名称会加剧这种怀疑。

除此之外,Node 的 javadoc 定义“getNodeValue()”为 Element 类型的节点返回 null。因此,您确实应该使用 getTextContent()。我不知道为什么这不会给你你想要的文字。

也许迭代你的标签节点的子节点,看看有哪些类型?

试过这段代码,它对我有用:

String xml = "<add job=\"351\">\n" +
             "    <tag>foobar</tag>\n" +
             "    <tag>foobar2</tag>\n" +
             "</add>";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
ByteArrayInputStream bis = new ByteArrayInputStream(xml.getBytes());
Document doc = db.parse(bis);
Node n = doc.getFirstChild();
NodeList nl = n.getChildNodes();
Node an,an2;

for (int i=0; i < nl.getLength(); i++) 
    an = nl.item(i);
    if(an.getNodeType()==Node.ELEMENT_NODE) 
        NodeList nl2 = an.getChildNodes();

        for(int i2=0; i2<nl2.getLength(); i2++) 
            an2 = nl2.item(i2);
            // DEBUG PRINTS
            System.out.println(an2.getNodeName() + ": type (" + an2.getNodeType() + "):");
            if(an2.hasChildNodes()) System.out.println(an2.getFirstChild().getTextContent());
            if(an2.hasChildNodes()) System.out.println(an2.getFirstChild().getNodeValue());
            System.out.println(an2.getTextContent());
            System.out.println(an2.getNodeValue());
        
    

输出是:

#text: type (3): foobar foobar
#text: type (3): foobar2 foobar2

【讨论】:

现在我也在打印 .getNodeName().. 它返回正确的值(标签) 我的标签元素没有子元素:/ 如果我尝试简单地使用 an2.getFirstChild().getTextContent() 或类似的东西,它会抛出 NullPointerException 尝试使用 getChildElements 而不是 getFirstChild()。也许 getFirstChild() 出于某种原因跳过了 Element 类型的节点? 我遇到过类似的情况,我有一个子节点,需要提取其内容。我有调试语句以确保我到达了正确的节点,但与 jsight 在他的解决方案中给出的不同,没有真正的输出。我已经从字面上复制粘贴了他的代码和事件,然后它不适用于示例。 有没有办法获取节点的外部标记,例如foobar ?【参考方案2】:

如果您的 XML 非常深入,您可能需要考虑使用 JRE 附带的 XPath,这样您就可以更轻松地访问内容:

String text = xp.evaluate("//add[@job='351']/tag[position()=1]/text()", 
    document.getDocumentElement());

完整示例:

import static org.junit.Assert.assertEquals;
import java.io.StringReader;    
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;    
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

public class XPathTest 

    private Document document;

    @Before
    public void setup() throws Exception 
        String xml = "<add job=\"351\"><tag>foobar</tag><tag>foobar2</tag></add>";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        document = db.parse(new InputSource(new StringReader(xml)));
    

    @Test
    public void testXPath() throws Exception 
        XPathFactory xpf = XPathFactory.newInstance();
        XPath xp = xpf.newXPath();
        String text = xp.evaluate("//add[@job='351']/tag[position()=1]/text()",
                document.getDocumentElement());
        assertEquals("foobar", text);
    

【讨论】:

不幸的是,这是一项教育工作,我必须使用 DOM api:/ 谢谢,这个完整的例子(带进口)在与其他类似的解决方案苦苦挣扎后真的帮助了我。【参考方案3】:

我用的是一个很老的java。 Jdk 1.4.08 和我有同样的问题。我的Node 类没有getTextContent() 方法。我不得不使用Node.getFirstChild().getNodeValue() 而不是Node.getNodeValue() 来获取节点的值。这对我来说是固定的。

【讨论】:

【参考方案4】:

如果您对vtd-xml 持开放态度,它在performance and memory efficiency 方面都表现出色,下面是您正在寻找的代码......在 XPath 和手动导航中......整体代码非常简洁和更容易理解...

import com.ximpleware.*;
public class queryText 
    public static void main(String[] s) throws VTDException
        VTDGen vg = new VTDGen();
        if (!vg.parseFile("input.xml", true))
            return;
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        // first manually navigate
        if(vn.toElement(VTDNav.FC,"tag"))
            int i= vn.getText();
            if (i!=-1)
                System.out.println("text ===>"+vn.toString(i));
            
            if (vn.toElement(VTDNav.NS,"tag"))
                i=vn.getText();
                System.out.println("text ===>"+vn.toString(i));
            
        

        // second version use XPath
        ap.selectXPath("/add/tag/text()");
        int i=0;
        while((i=ap.evalXPath())!= -1)
            System.out.println("text node ====>"+vn.toString(i));
        
    

【讨论】:

以上是关于使用 Java DOM 获取 XML 节点文本值的主要内容,如果未能解决你的问题,请参考以下文章

Java获取XML节点总结之读取XML文档节点

Java:简单的解析XML文件之使用DOM解析

java解析xml的几种方式哪种最好?

java中dom4j解析xml文件怎么获取节点属性

XML DOM

在 Java DOM 中获取节点的内部 XML 作为字符串