it-swarm.dev

Spazio dei nomi XML che rompe il mio xpath!

Ho il seguente XML:

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

Questa è una versione ridotta di XML restituita da un servizio Web di SharePoint. Ho anche il seguente xPath:

/List/Fields/Field

Quando rimuovo xmlns dal mio XML, xPath funziona bene. Quando è lì il mio xPath non trova nulla. C'è qualcosa che dovrei fare diversamente con il mio xPath? La modifica dell'XML non è un'opzione.

80
Abe Miessler

Ho anche il seguente xPath:

/List/Fields/Field 

Quando rimuovo xmlns dal mio XML, xPath funziona bene. Quando è lì il mio xPath non trova nulla

Se non è possibile registrare un'associazione dello spazio dei nomi e non è possibile utilizzare (supponendo che il prefisso registrato sia "x"):

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

poi c'è un altro modo:

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

L'elemento Elenco è stato definito con uno spazio dei nomi predefinito e questo viene adottato da tutti gli elementi all'interno.

È quindi necessario ignorare lo spazio dei nomi degli elementi in questo modo:

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

ma questo significa che xpath raccoglierà qualsiasi altro elemento con Elenco - Campi - Campo

È possibile eseguire un controllo dello spazio dei nomi e un controllo del nome locale in questo modo:

/*[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/']

Oppure puoi registrare lo spazio dei nomi con la libreria e quindi specificare esplicitamente il prefisso per quello spazio dei nomi e aggiungerlo all'espressione xpath, il cui metodo dipende dalla libreria che stai utilizzando.

44
rogermushroom

Molto probabilmente dovrai registrare lo uri dello spazio dei nomi nella tua libreria xpath. A seconda della libreria, potrebbe essere possibile utilizzare il prefisso "predefinito" oppure potrebbe essere necessario assegnargli un prefisso denominato e utilizzarlo nelle query xpath.

Ad esempio, in php (dato che non hai specificato una lingua) usando DOMXPath potresti fare qualcosa del genere:

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

Ho appena avuto questo problema durante l'utilizzo di Xalan-c

Il bit che inizialmente non ho capito è che gli alias/prefissi dello spazio dei nomi XPath o XSLT possono essere diversi da quelli del documento, a seconda del risolutore dello spazio dei nomi.

Sembra che se nel documento è presente uno spazio dei nomi, non riesce a far corrispondere un elemento percorso a meno che non venga utilizzato uno spazio dei nomi. (standard ma non sempre seguito?)

XalanDocumentPrefixResolver eseguirà il mapping degli spazi dei nomi XPath o XSLT sull'URI e proverà a fornire loro l'id ottenendo il prefisso - dove non esiste un prefisso, utilizza il nome trasformato in xmlns

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

In alternativa puoi creare il tuo risolutore, ma richiede comunque uno spazio dei nomi minimo utilizzato in xpath :(

Eccone uno che ho hackerato insieme durante i test, nessuna garanzia di memoria

// 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