2010-05-13 6 views
0

Fonctionnellement, les deux blocs devraient être les mêmesJava lecture élément XML sans préfixe, mais dans le cadre d'un espace de noms

<soapenv:Body> 
    <ns1:login xmlns:ns1="urn:soap.sof.com"> 
    <userInfo> 
     <username>superuser</username> 
     <password>qapass</password> 
    </userInfo> 
    </ns1:login> 
</soapenv:Body> 

----------------------- 

<soapenv:Body> 
    <ns1:login xmlns:ns1="urn:soap.sof.com"> 
    <ns1:userInfo> 
     <ns1:username>superuser</ns1:username> 
     <ns1:password>qapass</ns1:password> 
    </ns1:userInfo> 
    </ns1:login> 
</soapenv:Body> 

Cependant, comment quand je lus à l'aide AXIS2 et je l'ai testé avec java6 ainsi, J'ai un problème.

MessageFactory factory = MessageFactory.newInstance(); 
SOAPMessage soapMsg = factory.createMessage(new MimeHeaders(), SimpleTest.class.getResourceAsStream("LoginSoap.xml")); 

SOAPBody body = soapMsg.getSOAPBody(); 

NodeList nodeList = body.getElementsByTagNameNS("urn:soap.sof.com", "login"); 
System.out.println("Try to get login element" + nodeList.getLength()); // I can get the login element 

Node item = nodeList.item(0); 
NodeList elementsByTagNameNS = ((Element)item).getElementsByTagNameNS("urn:soap.sof.com", "username"); 
System.out.println("try to get username element " + elementsByTagNameNS.getLength()); 

Donc, si je remplace la 2e getElementsByTagNameNS avec ((Element) Point) .getElementsByTagName ("nom d'utilisateur") ;, je suis en mesure d'obtenir l'élément de nom d'utilisateur. Est-ce que le nom d'utilisateur n'a pas l'espace de noms ns1 même s'il n'a pas le préfixe? Suis-je supposé garder une trace de la portée de l'espace de noms pour lire un élément? Ne serait-il pas méchant si mes éléments xml sont profonds? Y at-il une solution de contournement où je peux lire l'élément dans l'espace de noms ns1 sans savoir si un préfixe est défini?

Répondre

1

Réponse courte est non, ces documents ne sont pas les mêmes. L'espace de noms n'est pas hérité par les éléments, et en définissant un préfixe, votre espace de noms ne fonctionne plus en tant qu'espace de noms par défaut pour le document.

Ces deux seraient les mêmes:

<soapenv:Body> 
    <login xmlns="urn:soap.sof.com"> 
    <userInfo> 
     <username>superuser</username> 
     <password>qapass</password> 
    </userInfo> 
    </login> 
</soapenv:Body> 

----------------------- 

<soapenv:Body> 
    <ns1:login xmlns:ns1="urn:soap.sof.com"> 
    <ns1:userInfo> 
     <ns1:username>superuser</ns1:username> 
     <ns1:password>qapass</ns1:password> 
    </ns1:userInfo> 
    </ns1:login> 
</soapenv:Body> 

Pour une façon plus robuste pour lire le document, vous devriez probablement dans la compilation des déclarations XPath. Les problèmes d'espace de noms sont seulement l'un des problèmes liés à l'utilisation des méthodes de commodité getElementsByTagName (NS).

- Edition -

Xpath lui-même est assez basique. Par exemple, //userInfo sélectionnez tous les éléments userInfo à n'importe quel niveau. //login/userInfo sélectionnez tous les éléments userInfo qui sont les enfants d'un login à n'importe quel niveau. Comme tout le reste, il devient plus compliqué quand vous devez commencer à ajouter des espaces de noms.

private NamespaceContext ns = new NamespaceContext() { 
public String getNamespaceURI(String prefix) { 
if (prefix.equals("urn") return "urn:soap.sof.com"; 
else return XMLConstants.NULL_NS_URI; 
} 
public String getPrefix(String namespace) { 
throw new UnsupportedOperationException(); 
} 
public Iterator getPrefixes(String namespace) { 
throw new UnsupportedOperationException(); 
}}; 

XPathFactory xpfactory = XPathFactory.newInstance(); 
XPath xpath = xpfactory.newXPath(); 
xpath.setNamespaceContext(ns); 
NodeList nodes = (NodeList) xpath.evaluate("//urn:userInfo|//userInfo", myDom, XPathConstants.NODESET); 
//find all userInfo at any depth with either namespace. 

Cela fait longtemps que j'ai utilisé JAXP, mais je pense que c'est fondamentalement correct. Exécuter un xPath n'est pas lent, mais les compiler est. Vous pouvez les compiler vers une expression XPathExpression pour les performances, mais celles-ci ne sont pas thread-safe, vous ne pouvez donc pas les mettre en cache sur une servlet. Jamais c'est facile = /.

Si vous faites beaucoup de XML, je recommanderais d'utiliser Jaxen au lieu de JAXP. (D'un autre coté, si vous faites très peu de XML et que c'est juste un sur le frontal, peut-être que getElementsByTagName n'est pas la pire chose :) :)

+0

D'après ce document http://www.rpbourret.com /xml/NamespacesFAQ.htm, l'espace de noms hérite des éléments. En outre, le corps SOAP supérieur est généré par les stubs AXIS2 (créés par wsdl2java de AXIS2). Tous les types complexes sont définis dans l'espace de noms cible urn: soap.sof.com. Si l'espace de noms hérite d'éléments, AXIS n'aurait pas créé d'éléments sans préfixe, ai-je tort? – wsxedc

+0

Le préfixe ns1 est dans la portée, mais un élément sans préfixe se trouve dans l'espace de nom par défaut, pas dans l'espace de nom de son parent, et aucun espace de noms par défaut n'est déclaré. – Affe

+0

Pouvez-vous me montrer un exemple de code pour utiliser XPath? Serait-il beaucoup plus lent par rapport à l'utilisation de getElementByTag? – wsxedc

Questions connexes