2009-04-21 2 views
35

Я не могу получить текстовое значение с Node.getNodeValue(), Node.getFirstChild().getNodeValue() или с Node.getTextContent().Получение значения XML-узла в Java DOM

Мой 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

Было бы полезно, если бы вы четко указали, что именно в настоящее время выполняется переменная 'n', документ или элемент documentElement? – AnthonyWJones

+1

Я добавил 'n' часть декларации – Emilio

ответ

45

Я распечатал результат an2.getNodeName(), а также для целей отладки. Я предполагаю, что ваш код обхода дерева не сканирует узлы, которые вы так думаете. Это подозрение усиливается из-за отсутствия проверки имен узлов в вашем коде.

Кроме этого, javadoc для узла определяет «getNodeValue()» для возврата null для узлов типа Element. Поэтому вы действительно должны использовать 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 
+1

теперь я тоже печатаю .getNodeName() .. и он возвращает правильное значение (тег) – Emilio

+0

Мой элемент тега не имеет дочерних элементов:/Если я попробую просто с a2. getFirstChild(). getTextContent() или аналогично ему бросает исключение NullPointerException – Emilio

+0

Попробуйте использовать getChildElements вместо getFirstChild(). Возможно, getFirstChild() по какой-то причине пропускает элементы, набранные элементом? – jsight

17

Если ваш 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); 
    } 
} 
+0

Неудачно является образовательным заданием, и я должен использовать DOM apis:/ – Emilio

+0

Можете ли вы использовать JDOM API? С этим работать гораздо проще. – jdigital

+0

Спасибо, этот полный пример (с импортом) действительно помог мне после борьбы с другими подобными решениями. –

1

Я использую очень старую java. Jdk 1.4.08, и у меня была такая же проблема. Класс Node для меня не имел метода getTextContent(). Я должен был использовать Node.getFirstChild().getNodeValue() вместо Node.getNodeValue(), чтобы получить значение узла. Это исправлено для меня.

1

Если вы открыты для 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)); 
     } 
    } 
} 
Смежные вопросы