使用 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 在他的解决方案中给出的不同,没有真正的输出。我已经从字面上复制粘贴了他的代码和事件,然后它不适用于示例。 有没有办法获取节点的外部标记,例如如果您的 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 节点文本值的主要内容,如果未能解决你的问题,请参考以下文章