SelectSingleNode retourner null connu un bon nœud xml chemin à l'aide de XPath
Considérer ce document XML simple. Le XML sérialisé montré ici est le résultat d'un XmlSerializer à partir d'un complexe POCO objet dont le schéma je n'ai aucun contrôle sur.
<My_RootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="">
<id root="2.16.840.1.113883.3.51.1.1.1" extension="someIdentifier" xmlns="urn:hl7-org:v3" />
<creationTime xsi:nil="true" xmlns="urn:hl7-org:v3" />
</My_RootNode>
L'objectif est d'extraire la valeur de l'attribut d'extension sur l'id de nœud. Dans ce cas, nous utilisons le SelectSingleNode méthode, et une expression XPath en tant que tel:
XmlNode idNode = myXmlDoc.SelectSingleNode("/My_RootNode/id");
//idNode is evaluated to null at this point in the debugger!
string msgID = idNode.Attributes.GetNamedItem("extension").Value;
Le problème est que le SelectSingleNode
méthode renvoie null pour l'expression XPath.
Question: toutes les idées sur cette requête XPath de l'exactitude, ou pourquoi l'appel de cette méthode + expression XPath doit retourner une valeur nulle? Peut-être les espaces de noms sont une partie du problème?
- Première chose à faire est de vérifier si le document XML a été correctement chargé. Je peux voir un vide attribut xmlns à la fin du nœud racine - est-ce que le droit?
- Correct, nous sommes à la recherche à un XmlDocument qui a chargé la chaîne de production d'un XmlSerializer.
- est-ce un gros document (HL7!)? Si oui, alors vous pouvez essayer de sérialisation directement dans le XmlDocument. Si vous voulez un exemple de cela, laissez-moi savoir.
Vous devez vous connecter pour publier un commentaire.
Je soupçonne fortement que le problème est de le faire avec des espaces de noms. Essayer de se débarrasser de l'espace de noms et vous serez amende - mais, évidemment, ce qui n'aidera pas dans votre cas réel, où je suppose que le document est fixe.
Je ne me souviens pas désinvolte comment définir un espace de noms dans une expression XPath, mais je suis sûr que c'est ça le problème.
EDIT: Ok, j'ai rappelé comment le faire maintenant. Il n'est pas très agréable si vous avez besoin de créer un
XmlNamespaceManager
pour elle. Voici un exemple de code qui fonctionne avec votre exemple de document:Si vous souhaitez ignorer les espaces de noms complètement, vous pouvez utiliser ceci:
Cela devrait fonctionner dans votre cas sans enlever les espaces de noms:
Désolé, vous avez oublié l'espace de noms. Vous avez besoin de:
En fait, que ce soit ici ou dans les services web, obtenir la valeur null de retour d'une opération XPath ou tout ce qui dépend de XPath indique généralement un problème avec les espaces de noms XML.
Bien... j'ai eu le même problème et c'était un mal de tête. Puisque je n'ai pas beaucoup de soins sur l'espace de noms ou le schéma xml, je viens de supprimer ces données à partir de mon xml et il a résolu tous mes problèmes. Peut-être pas la meilleure réponse? Probablement, mais si vous ne voulez pas faire face à tout cela et vous en charge UNIQUEMENT sur les données (et de ne pas utiliser le format xml pour une autre tâche) suppression de l'espace de noms peut résoudre votre problèmes.
Il suffit de construire à résoudre les problèmes d'espace de noms, dans mon cas, j'ai été en cours d'exécution dans des documents avec plusieurs espaces de noms et nécessaires pour gérer les espaces de noms correctement. J'ai écrit la fonction ci-dessous pour obtenir un espace de noms gestionnaire de traiter avec n'importe quel espace de noms dans le document:
La règle à garder à l'esprit est: si votre document spécifie un
namespace
, vous DEVEZ utiliser unXmlNamespaceManager
à votre appel à l'SelectNodes()
ouSelectSingleNode()
. C'est une bonne chose.Voir l'article Avantages des espaces de noms . Jon Skeet fait un excellent travail dans sa réponse montrant comment utiliser
XmlNamespaceManager
. (Cette réponse devrait vraiment être juste un commentaire sur cette réponse, mais je n'arrive pas à avoir assez de Points de Rep pour le commentaire.)simplement utiliser /id/au lieu de /id. Il fonctionne très bien dans mon code
Roisgoen réponse a fonctionné pour moi, mais pour le rendre plus général, vous pouvez utiliser une RegEx:
Je reconnais que ce n'est pas une bonne pratique de réponse, mais c'est une solution facile et parfois c'est tout ce dont nous avons besoin.