Winapi 使用XPath查询节点时如何指定命名空间? 短版
您可以通过以下方式在.NET中执行此操作:Winapi 使用XPath查询节点时如何指定命名空间? 短版,winapi,com,msxml,msxml6,Winapi,Com,Msxml,Msxml6,您可以通过以下方式在.NET中执行此操作: XmlNode.SelectNodes(query, selectionNamespaces); 你能用javascript做吗 你能用msxml做吗 尝试一个: 尝试B: 尝试C: 长版本 给定一个包含xml片段的 <row> <cell>a</cell> <cell>b</cell> <cell>c</cell> </row>
XmlNode.SelectNodes(query, selectionNamespaces);
你能用javascript做吗
你能用msxml做吗
尝试一个:
尝试B:
尝试C:
长版本
给定一个包含xml片段的
<row>
<cell>a</cell>
<cell>b</cell>
<cell>c</cell>
</row>
这将返回一个IXMLDOMNodeList:
A.
B
C
那很好
但是名称空间打破了它
如果XML片段来自具有命名空间的文档,例如:
<row xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<cell>a</cell>
<cell>b</cell>
<cell>c</cell>
</row>
你得到你的手机:
A.
B
C
但这对节点不起作用
IXMLDOMNode具有
选择节点法
将指定的模式匹配操作应用于此节点的上下文,并将匹配节点的列表作为IXMLDOMNodeList返回
评论
有关在名称空间中使用selectNodes方法的更多信息,请参阅主题
但在对DOM节点发出XPath查询时,无法指定选择名称空间
使用XPath查询节点时,如何指定名称空间
.NET解决方案
.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
完全极小示例
这在MSDN上得到了回答: 更新: 但是,请注意,在第二个示例XML中,将xmlns:peant添加到SelectionNamespaces属性时,XPath查询的命名空间中不包含和元素。这就是为什么找不到元素的原因 要将它们正确地放入命名空间,您必须: 将名称空间声明更改为使用xmlns=而不是xmlns:ss=: A. B C 使用and代替and: A. B C SelectionNamespaces属性不会神奇地将元素放入命名空间中,它只指定哪些命名空间可供XPath查询使用。XML本身必须根据需要将元素放入适当的名称空间 更新: 在您的新示例中,cells:=row.selectNodes'/ss:row/ss:cell';不起作用,因为XPath查询使用的是绝对路径,其中前导/起始于文档根,并且XML文档顶部没有元素,只有一个元素。这就是为什么行:=doc.selectNodes'/ss:worksheet/ss:row';工作 如果要执行从被查询节点开始的XPath查询,请不要使用绝对路径,而是使用相对路径:
cells := row.selectNodes('ss:row/ss:cell');
或者简单地说:
cells := row.selectNodes('ss:cell');
node.ownerDocument.setPropertySelectionNamespaces…@Ben这是个好主意。不幸的是,它根本不起作用——它根本不返回任何节点。你有JSFIDLE吗?@Ben我没有使用javascript,我使用的是原生Win32 COM msxml。你有JSFIDLE吗?我没有,但应该可以用JScript/Windows脚本主机重现这个问题?据我所知,代码调用Document.setProperty。i、 它查询的是一个文档而不是一个节点,因为它是整个DOM文档的属性,而不是单个节点的属性。运行XPath查询时,无论在哪个节点上运行查询,它都将使用文档的current SelectedNamespaces属性解析查询中的命名空间;它根本不起作用。本已经提出了上述建议。@IanBoyd它确实有效,我以前用过。您注意到我在回答中添加的额外信息了吗?您说添加SelectionNamespaces属性并不会神奇地将元素放入名称空间中。为什么当我添加SelectionNamespace时,它会神奇地将元素放入适合我的命名空间中?在问题中添加了完整的最小示例。
<row xmlns:ss="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<cell>a</cell>
<cell>b</cell>
<cell>c</cell>
</row>
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");
HRESULT selectNodes(
BSTR expression,
IXMLDOMNodeList **resultList);
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("peanut", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
cells = row.SelectNodes("/peanut:row/peanut:cell", ns);
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.
cells := row.selectNodes('ss:row/ss:cell');
cells := row.selectNodes('ss:cell');