web-dev-qa-db-ja.com

Xml名前空間が私のxpathを壊しています!

次のXMLがあります。

<List xmlns="http://schemas.Microsoft.com/sharepoint/soap/">
 <Fields>
   <Field>
   </Field>
 </Fields>
</List>

これは、SharePoint Webサービスから返されるXMLのスリムバージョンです。次のxPathもあります。

/List/Fields/Field

XMLからxmlnsを削除すると、xPathは正常に機能します。そこにあるとき、私のxPathは何も見つけません。 xPathで別の方法でやるべきことはありますか? XMLの変更はオプションではありません。

80
Abe Miessler

次のxPathもあります。

/List/Fields/Field 

XMLからxmlnsを削除すると、xPathは正常に機能します。それがそこにあるとき、私のxPathは何も見つけません

名前空間バインディングを登録できず、使用できない場合(登録されたプレフィックスが「x」であると仮定):

/x:List/x:Fields/x:Field

その後、別の方法があります

/*[name()='List']/*[name()='Fields']/*[name()='Field']
102

List要素はデフォルトの名前空間で定義されており、これは内部のすべての要素に採用されています。

したがって、次のように要素の名前空間を無視する必要があります。

/*[local-name()='List']/*[local-name()='Fields]/*[local-name()='Field]

しかし、これはxpathがList-Fields-Fieldで他の要素を取得することを意味します

次のような名前空間チェックとローカル名チェックを実行できます。

/*[local-name()='List' and namespace-uri()='http://schemas.Microsoft.com/sharepoint/soap/']/*[local-name()='Fields' and namespace-uri()='http://schemas.Microsoft.com/sharepoint/soap/']/*[local-name()='Field' and namespace-uri()='http://schemas.Microsoft.com/sharepoint/soap/']

または、名前空間をライブラリに登録し、その名前空間のプレフィックスを明示的に指定して、使用しているライブラリに依存するメソッドをxpath式に追加できます。

44
rogermushroom

ほとんどの場合、その名前空間uriをxpathライブラリに登録する必要があります。ライブラリによっては、「デフォルト」プレフィックスを使用できる場合もあれば、名前付きプレフィックスを指定してxpathクエリで使用する必要がある場合もあります。

たとえば、PHPで(言語を指定しなかったため)DOMXPathを使用すると、次のようなことができます。

$xpath = new DOMXPath($document);
$xpath->registerNamespace('x', 'http://schemas.Microsoft.com/sharepoint/soap/');
$xpath->query('/x:List/x:Fields/x:Field');
16
Anomie

Xalan-cを使用しているときにこの問題が発生しました。

私が最初にまったく得なかったのは、XPathまたはXSLT名前空間のエイリアス/プレフィックスが、名前空間リゾルバに応じてドキュメントのエイリアス/プレフィックスと異なる場合があるということです。

ドキュメントに名前空間がある場合、名前空間が使用されない限り、パス要素との一致に失敗するようです。 (標準ですが、常に従わない?)

XalanDocumentPrefixResolverは、XPathまたはXSLT名前空間をURIにマップし、接頭辞を取得してIDを与えます-接頭辞がない場合、xmlnsになった名前を使用します

/xmlns:List/xmlns:Fields/xmlns:Field

または、独自のリゾルバを作成することもできますが、それでもxpathで使用される最小限の名前空間が必要です:(

これはテスト中に一緒にハッキングしたもので、メモリの保証はありません

// don't care what prefix given, there can only be the one
struct NoPrefixResolver : public xalanc::PrefixResolver {

    NoPrefixResolver(const xalanc::XalanDOMString&   theURI) : m_uri(theURI){}

    virtual const xalanc::XalanDOMString*
        getNamespaceForPrefix(const xalanc::XalanDOMString&     prefix) const {
        return &m_uri;
    }

    virtual const xalanc::XalanDOMString&   getURI() const {
        return m_uri;
    }

    const xalanc::XalanDOMString    m_uri;
};

/x:List/x:Fields/x:Field 
/a:List/b:Fields/c:Field 
1
Greg Domjan