Получение XML Node текстового значения с помощью Java DOM
Я не могу получить текстовое значение с помощью Node.getNodeValue()
, Node.getFirstChild().getNodeValue()
или Node.getTextContent()
.
Мой XML похож на
<add job="351">
<tag>foobar</tag>
<tag>foobar2</tag>
</add>
И я пытаюсь получить значение тега (отлично работает нетекстовый элемент). Мой код 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_
...
Спасибо за помощь.
Ответы
Ответ 1
Я бы распечатал результат an2.getNodeName()
, а также для целей отладки. Я предполагаю, что ваш код обхода дерева не сканирует узлы, которые вы так думаете. Это подозрение усиливается из-за отсутствия проверки имен node в вашем коде.
Кроме этого, javadoc для node определяет " getNodeValue()" для возврата null для узлов типа Element. Поэтому вы действительно должны использовать getTextContent(). Я не уверен, почему это не даст вам текст, который вы хотите.
Возможно, повторите попытку дочерних элементов вашего тега node и посмотрите, какие типы существуют?
Пробовал этот код, и он работает для меня:
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
Ответ 2
Если ваш XML будет достаточно глубоким, вам может потребоваться использовать XPath, который поставляется с вашей JRE, поэтому вы можете получить доступ к содержимому гораздо легче, используя:
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);
}
}
Ответ 3
Я использую очень старую java. Jdk 1.4.08, и у меня была такая же проблема. Класс Node
для меня не имел метода getTextContent()
. Я должен был использовать Node.getFirstChild().getNodeValue()
вместо Node.getNodeValue()
, чтобы получить значение node. Это исправлено для меня.
Ответ 4
Если вы открыты для vtd-xml, который превосходит как производительность и эффективность использования памяти, ниже приведен код, который нужно делать, как в 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));
}
}
}