2009-04-21 7 views
35

Je ne peux pas extraire de valeur de texte avec Node.getNodeValue(), Node.getFirstChild().getNodeValue() ou avec Node.getTextContent().Obtention d'une valeur de texte de noeud XML avec Java DOM

Mon XML est comme

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

Et je suis en train d'obtenir valeur tag (élément non textuel aller chercher des œuvres bien). Mon code Java ressemble

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()); 
     } 
    } 
} 

Il imprime

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

Merci pour l'aide.

+1

Il serait utile que vous indiquiez clairement ce que la variable 'n' contient actuellement exactement, le Document ou le documentElement? – AnthonyWJones

+1

J'ai ajouté 'n' déclaration partie – Emilio

Répondre

45

J'imprimerais également le résultat de an2.getNodeName() à des fins de débogage. Ma conjecture est que votre code d'exploration d'arbre ne rampe pas vers les nœuds que vous pensez qu'il est. Cette suspicion est renforcée par l'absence de vérification des noms de nœuds dans votre code. A part cela, javadoc pour Node définit "getNodeValue()" pour renvoyer null pour les nœuds de type Element. Par conséquent, vous devriez vraiment utiliser getTextContent(). Je ne sais pas pourquoi cela ne vous donnerait pas le texte que vous voulez. Peut-être itérez-vous les enfants de votre noeud d'étiquette et voyez quels types sont là?

Essayé ce code et ça marche pour moi:

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()); 
     } 
    } 
} 

sortie était:

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

maintenant j'imprime aussi .getNodeName() .. et il renvoie la bonne valeur (tag) – Emilio

+0

Mon élément de balise n'a pas childs:/Si j'essaye simplement avec an2. getFirstChild(). getTextContent() ou similaire lance une NullPointerException – Emilio

+0

Essayez d'utiliser getChildElements au lieu de getFirstChild(). Peut-être que getFirstChild() saute des nœuds typés Element pour une raison quelconque? – jsight

17

Si votre XML va assez profond, vous voudrez peut-être envisager d'utiliser XPath, qui vient avec votre JRE , afin que vous puissiez accéder au contenu beaucoup plus facilement en utilisant:

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

exemple complet:

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

Malheureusement, est un travail éducatif et je dois utiliser DOM apis:/ – Emilio

+0

Pouvez-vous utiliser l'API JDOM? C'est beaucoup plus facile de travailler avec. – jdigital

+0

Merci, cet exemple complet (avec les importations) m'a vraiment aidé après avoir lutté avec d'autres solutions similaires. –

1

J'utilise un très vieux java. Jdk 1.4.08 et moi avions le même problème. La classe Node pour moi n'avait pas la méthode getTextContent(). J'ai dû utiliser Node.getFirstChild().getNodeValue() au lieu de Node.getNodeValue() pour obtenir la valeur du nœud. Ceci fixé pour moi.

1

Si vous êtes ouvert à vtd-xml, qui excelle aux deux performance and memory efficiency, voici le code pour faire ce que vous cherchez ... dans XPath et la navigation manuelle ... le code global est beaucoup plus concis et plus facile à comprendre ...

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)); 
     } 
    } 
} 
Questions connexes