Especificar espacio de nombres al consultar el DOM con XPath

En este artículo se describe que debe usar nombres completos al usar la consulta XPath con los métodos selectSingleNode y selectNodes del IXMLDOMNode objeto .

Versión original del producto: Analizador XML de Microsoft
Número de KB original: 294797

Resumen

Con la versión 3.0 del analizador XML (MSXML), XPath proporciona una manera cómoda de consultar documentos XML y devolver un nodo o un conjunto de nodos. Cuando se usa XPath la consulta con los selectSingleNode métodos y selectNodes del IXMLDOMNode objeto , debe usar nombres completos. Por ejemplo, para seleccionar el nodo Libro con los siguientes datos XML:

<?xml version ="1.0"?>
<a:Books xmlns:a="x-schema:bookschema.xml" >
    <a:Book>
        <title>Presenting XML</title>
        <author>Richard Light</author>
    </a:Book>
</a:Books>

Si usamos como alias del x-schema:bookschema.xml identificador uniforme de recursos (URI), la consulta XPath correspondiente es la siguiente:

pXMLDoc->setProperty("SelectionNamespaces","xmlns:a='x-schema:bookschema.xml'");
pXMLDoc->documentElement->selectNodes("/a:Books/a:Book");

En este caso, el uso del nombre completo es sencillo. Sin embargo, cuando se usa el espacio de nombres predeterminado, el uso del nombre completo puede ser más difícil, como en el ejemplo siguiente:

<?xml version ="1.0"?>
<Books xmlns="x-schema:bookschema.xml" >
    <Book>
        <title>Presenting XML</title>
        <author>Richard Light</author>
    </Book>
</Books>

Nota:

No se usa ningún prefijo en las etiquetas de nodo. El nombre completo debe seguir utilizándose dentro de la consulta XPath; de lo contrario, la consulta (por ejemplo, /Books/Book) no devuelve ningún resultado porque no hay nodos coincidentes.

Más información

Se proporciona el siguiente ejemplo de Visual C++ para mostrar la técnica.

Para especificar el espacio de nombres al consultar el DOM con XPath, siga estos pasos:

  1. Cree un proyecto de consola win32 y agregue un nuevo archivo .cpp al proyecto. Pegue el código siguiente en el archivo .cpp y asigne al archivo el nombre Test.cpp:

    #include <stdio.h>
    
    #import "msxml3.dll"
    using namespace MSXML2;
    
    void dump_com_error(_com_error &e);
    
    int main(int argc, char* argv[])
    {
        CoInitialize(NULL);
        try{
            IXMLDOMDocument2Ptr pXMLDoc;
            HRESULT hr = pXMLDoc.CreateInstance(__uuidof(DOMDocument));
    
            pXMLDoc->async = false; // default - true,
    
            pXMLDoc->validateOnParse = true;
    
            hr = pXMLDoc->load("books.xml");
    
            if(hr!=VARIANT_TRUE)
            {
                IXMLDOMParseErrorPtr pError;
    
                pError = pXMLDoc->parseError;
                _bstr_t parseError =_bstr_t("At line ")+ _bstr_t(pError->Getline()) + _bstr_t("\n")+
                _bstr_t(pError->Getreason());
                MessageBox(NULL,parseError, "Parse Error",MB_OK);
                return -1;
            }
    
            hr = pXMLDoc->setProperty("SelectionLanguage", "XPath");
            hr = pXMLDoc->setProperty("SelectionNamespaces", "xmlns:a='x-schema:bookschema.xml'");
    
            IXMLDOMNodeListPtr pNodeList;
            pNodeList = pXMLDoc->documentElement->selectNodes("/a:Books/a:Book");
            int count = pNodeList->Getlength();
            char pLength[64];
            sprintf(pLength, "Total number of nodes selected is %d", count);
            MessageBox(NULL,pLength,"Test", MB_OK);
    
        }
        catch(_com_error &e)
        {
            dump_com_error(e);
            return -1;
        }
        return 0;
    }
    
    void dump_com_error(_com_error &e)
    {
        printf("Error\n");
        printf("\a\tCode = %08lx\n", e.Error());
        printf("\a\tCode meaning = %s", e.ErrorMessage());
        _bstr_t bstrSource(e.Source());
        _bstr_t bstrDescription(e.Description());
        printf("\a\tSource = %s\n", (LPCSTR) bstrSource);
        printf("\a\tDescription = %s\n", (LPCSTR) bstrDescription);
    }
    
  2. Guarde el siguiente XML como Books.xml en la misma carpeta del proyecto que Test.cpp.

    <?xml version ="1.0"?>
    <Books xmlns="x-schema:bookschema.xml" >
    <Book>
    <title>Presenting XML</title>
    <author>Richard Light</author>
    <pages>334</pages>
    </Book>
    <Book>
    <title>Mastering XML</title>
    <author>John Smith</author>
    <pages>209</pages>
    </Book>
    </Books>
    
  3. Guarde el siguiente XML como Bookschema.xml en la misma carpeta del proyecto que Test.cpp.

    <?xml version="1.0"?>
    <Schema xmlns="urn:schemas-microsoft-com:xml-data">
    <ElementType name="title" />
    <ElementType name="author" />
    <ElementType name="pages" />
    <ElementType name="Book" model="closed">
    <element type="title" />
    <element type="author" />
    <element type="pages" />
    </ElementType>
    <ElementType name="Books" model="closed">
    <element type="Book" />
    </ElementType>
    </Schema>
    
  4. Compile y ejecute la aplicación. Un cuadro de mensaje muestra el número de nodos devueltos por la XPath consulta. Vea los siguientes temas:

    • El mismo código de ejemplo se puede usar con un URI explícito como espacio de nombres.

    • En las líneas siguientes

      IXMLDOMDocument2Ptr pXMLDoc;
      ...
      hr = pXMLDoc->setProperty("SelectionLanguage", "XPath");
      hr = pXMLDoc->setProperty("SelectionNamespaces", "xmlns:a='x-schema:bookschema.xml'");
      ...
      pNodeList = pXMLDoc->documentElement->selectNodes("/a:Books/a:Book");
      

      el setProperty método no está disponible con la IXMLDOMDocument interfaz .

Un nombre completo (QName) se compone de un prefijo y una parte local. El prefijo proporciona el prefijo de espacio de nombres del nombre completo y debe estar asociado a un URI de espacio de nombres.

Referencias

Uso de XPath para realizar consultas en un espacio de nombres predeterminado definido por el usuario