この単純なXMLドキュメントを検討してください。ここに示すシリアル化されたXMLは、スキーマを制御できない複雑なPOCOオブジェクトのXmlSerializerの結果です。
<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>
目標は、idノードの拡張属性の値を抽出することです。この場合、SelectSingleNodeメソッドを使用し、XPath式を次のように指定します。
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;
問題は、特定のXPath式に対してSelectSingleNode
メソッドがnullを返すことです。
質問:このXPathクエリの正確性に関するアイデア、またはこのメソッド呼び出し+ XPath式がnull値を返す理由おそらく、名前空間は問題の一部ですか?
問題は名前空間に関係していると強く思う。名前空間を取り除けば大丈夫です-しかし、明らかに、それはドキュメントが修正されたと仮定する実際のケースでは役に立ちません。
XPath式で名前空間を指定する方法を覚えているわけではありませんが、それが問題だと確信しています。
編集:さて、私は今それを行う方法を覚えています。しかし、それはひどく快適ではありません-あなたはXmlNamespaceManager
を作成する必要があります。サンプルドキュメントで使用できるサンプルコードを次に示します。
using System;
using System.Xml;
public class Test
{
static void Main()
{
XmlDocument doc = new XmlDocument();
XmlNamespaceManager namespaces = new XmlNamespaceManager(doc.NameTable);
namespaces.AddNamespace("ns", "urn:hl7-org:v3");
doc.Load("test.xml");
XmlNode idNode = doc.SelectSingleNode("/My_RootNode/ns:id", namespaces);
string msgID = idNode.Attributes["extension"].Value;
Console.WriteLine(msgID);
}
}
名前空間を完全に無視したい場合は、これを使用できます:
static void Main(string[] args)
{
string xml =
"<My_RootNode xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"\">\n" +
" <id root=\"2.16.840.1.113883.3.51.1.1.1\" extension=\"someIdentifier\" xmlns=\"urn:hl7-org:v3\" />\n" +
" <creationTime xsi:nil=\"true\" xmlns=\"urn:hl7-org:v3\" />\n" +
"</My_RootNode>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNode idNode = doc.SelectSingleNode("/*[local-name()='My_RootNode']/*[local-name()='id']");
}
これは名前空間を削除せずにあなたのケースで動作するはずです:
XmlNode idNode = myXmlDoc.GetElementsByTagName("id")[0];
名前空間を忘れてしまいました。必要なもの:
XmlNamespaceManager ns = new XmlNamespaceManager(myXmlDoc.NameTable);
ns.AddNamespace("hl7","urn:hl7-org:v3");
XmlNode idNode = myXmlDoc.SelectSingleNode("/My_RootNode/hl7:id", ns);
実際、ここでもWebサービスでも、XPath操作またはXPathに依存するものからnullを取得することは、通常、XML名前空間に問題があることを示しています。
まあ...私は同じ問題を抱えていた、それは頭痛だった。名前空間やxmlスキーマについてはあまり気にしていないので、このデータをxmlから削除するだけで、すべての問題が解決しました。最良の答えではないでしょうか?おそらく、しかし、これらすべてに対処したくなくて、データだけに関心がある(そして他のタスクにxmlを使用しない)場合は、名前空間を削除することで問題が解決する可能性があります。
XmlDocument vinDoc = new XmlDocument();
string vinInfo = "your xml string";
vinDoc.LoadXml(vinInfo);
vinDoc.InnerXml = vinDoc.InnerXml.Replace("xmlns=\"http://tempuri.org\/\", "");
注意すべきルールは、ドキュメントでnamespace
を指定している場合、SelectNodes()
またはSelectSingleNode()
への呼び出しでXmlNamespaceManager
を使用する必要があります。それはいい。
記事 名前空間の利点 を参照してください。 Jon Skeetは、XmlNamespaceManager
の使用方法を示す彼の答えで素晴らしい仕事をしています。 (この回答は、実際にはその回答に対するコメントである必要がありますが、コメントするのに十分なRep Pointsがありません。)
名前空間の問題を解決するために構築するために、私の場合、複数の名前空間を持つドキュメントに遭遇し、名前空間を適切に処理する必要がありました。ドキュメント内のネームスペースを処理するネームスペースマネージャを取得するために、以下の関数を作成しました。
private XmlNamespaceManager GetNameSpaceManager(XmlDocument xDoc)
{
XmlNamespaceManager nsm = new XmlNamespaceManager(xDoc.NameTable);
XPathNavigator RootNode = xDoc.CreateNavigator();
RootNode.MoveToFollowing(XPathNodeType.Element);
IDictionary<string, string> NameSpaces = RootNode.GetNamespacesInScope(XmlNamespaceScope.All);
foreach (KeyValuePair<string, string> kvp in NameSpaces)
{
nsm.AddNamespace(kvp.Key, kvp.Value);
}
return nsm;
}
/ idの代わりに// idを使用します。私のコードではうまくいきます