使用XPath查询节点时如何指定命名空间?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用XPath查询节点时如何指定命名空间?相关的知识,希望对你有一定的参考价值。

Short Version

尝试A:

IXMLDOMNode.selectNodes(query); //no namespaces option

尝试B:

IXMLDOMNode.ownerDocument.setProperty("SelectionNamespaces", selectionNamespaces);
IXMLDOMNode.selectNodes(query); //doesn't work

尝试C:

IXMLDOMDocument3 doc;
doc.setProperty("SelectionNamespaces", selectionNamespaces);
IXMLDOMNodeList list = doc.selectNodes(...)[0].selectNodes(query); //doesn't work

Long Version

给定一个包含xml片段的IXMLDOMNode

<row>
    <cell>a</cell>
    <cell>b</cell>
    <cell>c</cell>
</row>

我们可以使用IXMLDOMNode.selectNodes方法来选择子元素:

IXMLDOMNode row = //...xml above

IXMLDOMNodeList cells = row.selectNodes("/row/cell");

这将返回IXMLDOMNodeList:

  • <cell>a</cell>
  • <cell>b</cell>
  • <cell>c</cell>

那没关系。

但命名空间打破了它

如果XML片段源自具有命名空间的文档,例如:

<row xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <cell>a</cell>
    <cell>b</cell>
    <cell>c</cell>
</row>

相同的XPath查询将不会,因为元素rowcell不存在;他们在另一个名称空间。

使用默认命名空间查询文档

如果您有完整的IXMLDOMDocument,则可以使用setProperty方法设置选择命名空间:

a b c

您可以通过为其命名来查询默认命名空间,例如:

  • 之前:xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  • 之后:xmlns:peanut="http://schemas.openxmlformats.org/spreadsheetml/2006/main"

然后你可以查询它:

IXMLDOMDocument3 doc = //...document xml above
doc.setProperty("SelectionNamespaces", "xmlns:peanut="http://schemas.openxmlformats.org/spreadsheetml/2006/main");

IXMLDOMNodeList cells = doc.selectNodes("/peanut:row/peanut:cell");

你得到你的细胞:

  • <cell>a</cell>
  • <cell>b</cell>
  • <cell>c</cell>

但这对节点不起作用

IXMLDOMNode有一个method to perform XPath queries:

selectNodes方法

将指定的模式匹配操作应用于此节点的上下文,并将匹配节点列表作为IXMLDOMNodeList返回。

HRESULT selectNodes(  
      BSTR expression,  
      IXMLDOMNodeList **resultList); 

备注

有关将selectNodes方法与命名空间一起使用的更多信息,请参阅setProperty Method主题。

但是,在针对DOM节点发出XPath查询时,无法指定选择命名空间。

使用XPath查询节点时如何指定命名空间?

.NET Solution

.NET的XmlNode提供了一个SelectNodes方法,该方法提供接受XmlNamespaceManager参数:

XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("peanut", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
cells = row.SelectNodes("/peanut:row/peanut:cell", ns);

但我不是在C#(我也不是Javascript)。什么是本机msxml6等价物?

编辑:我不是用Javascript(jsFiddle

Complete Minimal Example

program Project3;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, msxml, ActiveX;

procedure Main;
var
    s: string;
    doc: DOMDocument60;
    rows: IXMLDOMNodeList;
    row: IXMLDOMElement;
    cells: IXMLDOMNodeList;
begin
    s :=
            '<?xml version="1.0" encoding="UTF-16" standalone="yes"?>'+#13#10+
            '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'+#13#10+
            '<row>'+#13#10+
            '    <cell>a</cell>'+#13#10+
            '    <cell>b</cell>'+#13#10+
            '    <cell>c</cell>'+#13#10+
            '</row>'+#13#10+
            '</worksheet>';

    doc := CoDOMDocument60.Create;
    doc.loadXML(s);
    if doc.parseError.errorCode <> 0 then
        raise Exception.CreateFmt('Parse error: %s', [doc.parseError.reason]);

    doc.setProperty('SelectionNamespaces', 'xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main"');

    //Query for all the rows
    rows := doc.selectNodes('/ss:worksheet/ss:row');
    if rows.length = 0 then
        raise Exception.Create('Could not find any rows');

    //Do stuff with the first row
    row := rows[0] as IXMLDOMElement;

    //Get the cells in the row
    (row.ownerDocument as IXMLDOMDocument3).setProperty('SelectionNamespaces', 'xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main"');
    cells := row.selectNodes('/ss:row/ss:cell');
    if cells.length <> 3 then
        raise Exception.CreateFmt('Did not find 3 cells in the first row (%d)', [cells.length]);
end;

begin
  try
        CoInitialize(nil);
        Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

以上是关于使用XPath查询节点时如何指定命名空间?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 XPath 忽略命名空间

使用 xpath 访问具有命名空间的子节点

XPATH 帮助:使用 XPathNodeIterator 在命名空间中查找 XML 节点

XML查询命名空间和节点

如何将 XPath 与没有前缀的默认命名空间一起使用?

XPath 选择具有命名空间的节点