質問
XPath と名前空間のサポートの背後にあるストーリーは何ですか?仕様としての XPath は名前空間よりも優先されましたか?要素にデフォルトの名前空間が与えられているドキュメントがある場合:
<foo xmlns="uri" />
一部の XPath プロセッサ ライブラリが認識できないようです //foo
他の人はそうするのに対し、名前空間のためです。私のチームが考えたオプションは、正規表現を使用して名前空間プレフィックスを XPath に追加することです (名前空間プレフィックスは XmlNameTable 経由で追加できます)。しかし、XPath はノード テストに関しては非常に柔軟な言語であるため、これは脆弱に思えます。
これに適用される基準はありますか?
私のアプローチは少しハック的ですが、うまく機能するようです。を削除します xmlns
検索/置換を使用して宣言し、XPath を適用します。
string readyForXpath = Regex.Replace(xmldocument, "xmlns=\".+\"", String.Empty );
それは公平なアプローチですか、それともこれを別の方法で解決した人はいますか?
解決
私は、palacehorse が提案したものと同様のことを試みましたが、機能させることができませんでした。公開されたサービスからデータを取得していたので、xml を変更できませんでした。私は最終的に次のように XmlDocument と XmlNamespaceManager を使用しました。
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlWithBogusNamespace);
XmlNamespaceManager nSpace = new XmlNamespaceManager(doc.NameTable);
nSpace.AddNamespace("myNs", "http://theirUri");
XmlNodeList nodes = doc.SelectNodes("//myNs:NodesIWant",nSpace);
//etc
他のヒント
local-name() が必要です。
http://www.w3.org/TR/xpath#関数ローカル名
からベビーベッドへ http://jcooney.net/archive/2005/08/09/6517.aspx:
<foo xmlns='urn:foo'>
<bar>
<asdf/>
</bar>
</foo>
この式は「bar」要素と一致します。
//*[local-name()='bar']
これはそうではありません:
//bar
問題は、名前空間のない要素が NULL 名前空間にあると宣言されていることです。したがって、 //foo が「デフォルト」と見なす名前空間と一致した場合、NULL 名前空間内の要素を参照する方法がありません。
名前空間の接頭辞は単なる省略表記であり、実際の要素名 (修飾名、略して QName) は完全な名前空間とローカル名で構成されることにも注意してください。名前空間の接頭辞を変更しても、要素の「アイデンティティ」は変更されません。要素が同じ名前空間および同じローカル名にある場合、接頭辞が異なっていても、それは同じ種類の要素です。
XPath 2.0 (または XSLT 2.0) には、「デフォルトの xpath 名前空間」という概念があります。xsl:stylesheet 要素に xpath-default-namespace 属性を設定できます。
xslt を使用しようとしている場合は、スタイルシート宣言に名前空間を追加できます。これを行う場合は、接頭辞があることを確認する必要があります。接頭辞がないと機能しません。ソース XML にプレフィックスがない場合でも問題ありませんが、スタイルシートに独自のプレフィックスを追加します。
スタイルシート
<xsl:stylesheet
xmlns:fb="uri"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="fb:foo/bar">
<!-- do stuff here -->
</xsl:template>
</xsl:stylsheet>
あるいはそのようなものです。
libxml を使用すると、これが機能するようです:
http://xmlsoft.org/examples/xpath1.c
int
register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
xmlChar* nsListDup;
xmlChar* prefix;
xmlChar* href;
xmlChar* next;
assert(xpathCtx);
assert(nsList);
nsListDup = xmlStrdup(nsList);
if(nsListDup == NULL) {
fprintf(stderr, "Error: unable to strdup namespaces list\n");
return(-1);
}
next = nsListDup;
while(next != NULL) {
/* skip spaces */
while((*next) == ' ') next++;
if((*next) == '\0') break;
/* find prefix */
prefix = next;
next = (xmlChar*)xmlStrchr(next, '=');
if(next == NULL) {
fprintf(stderr,"Error: invalid namespaces list format\n");
xmlFree(nsListDup);
return(-1);
}
*(next++) = '\0';
/* find href */
href = next;
next = (xmlChar*)xmlStrchr(next, ' ');
if(next != NULL) {
*(next++) = '\0';
}
/* do register namespace */
if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
xmlFree(nsListDup);
return(-1);
}
}
xmlFree(nsListDup);
return(0);
}