C# 中 XmlNode.SelectSingleNode(string xpath) 的正确用法是啥?
Posted
技术标签:
【中文标题】C# 中 XmlNode.SelectSingleNode(string xpath) 的正确用法是啥?【英文标题】:What is the correct use of XmlNode.SelectSingleNode(string xpath) in C#?C# 中 XmlNode.SelectSingleNode(string xpath) 的正确用法是什么? 【发布时间】:2011-12-03 07:48:44 【问题描述】:我在处理一些 XML 文件时遇到了问题(在本文末尾)。
我编写了以下代码以获取与给定Job_Name
模式相关的Job_Id
数据,该模式的所有者Job_Owner
是运行程序的用户:
List<String> jobID = new List<String>();
XmlNodeList nodes = xml.SelectNodes("//Job");
foreach (XmlNode node in nodes)
innerNode = node.SelectSingleNode("//Job_Owner"); // SelectSingleNode here always selects the same node, but I thought it should be relative to node, not to nodes
if (!innerNode.InnerText.Contains(Environment.UserName))
continue;
innerNode = node.SelectSingleNode("//Job_Name");
if (!Regex.IsMatch(innerNode.InnerText, jobNamePattern, RegexOptions.Compiled))
continue;
innerNode = node.SelectSingleNode("//Job_Id");
jobID.Add(innerNode.InnerText);
我希望node.SelectSingleNode("//Job_Name")
只在node
表示的xml 代码下寻找一个名为Job_Name
的标签。
这似乎不是正在发生的事情,因为它总是返回相同的节点,在foreach
的哪个步骤它是无关紧要的(即从nodes
更改中选择的node
,但是node.SelectSingleNode("//Job_Name")
总是返回相同的内容)。
这段代码有什么问题?
提前致谢!
--
XML 文件如下所示:
<Data>
<Job>
<Job_Id>58282.minerva</Job_Id>
<Job_Name>sb_net4_L20_sType1</Job_Name>
<Job_Owner>mgirardis@minerva</Job_Owner>
<!--more tags-->
</Job>
<Job>
<!--etc etc etc-->
</Job>
<!--etc etc etc-->
</Data>
【问题讨论】:
【参考方案1】:我们使用 maXbox 脚本执行了一个大型 DOM /xml /SQL 例程:
函数 GetXMLFromURLAdr_IsSame_All(apath: string): boolean; 变量 xml,节点:Olevariant; //IXMLDOM文档; nodes_row,nodes_se,nodex:olevariant; i, j:整数; sr1,sr2,basenod,basenod2,filePrefix,mysql,odbcDSN,Auftrag:字符串; 开始 xml:= CreateOleObject('Microsoft.XMLDOM') as IXMLDocument; xml.async:= 假; if xml.load(apath) then writeln('xml path load success2'); 如果 xml.parseError.errorCode 0 那么 writeln('XML 加载错误:' + xml.parseError.reason); basenod:= '/WAB/Auftragsliste/Auftrag'; 节点行:= xml.SelectNodes(basenod); writeln('auftrag 节点总数:'+itoa(nodes_row.length)) 尝试 对于 j:= 0 到 nodes_row.length-1 开始 //nodes_se:= nodes_row.item[j] 节点:= nodes_row.item[j] // writeln(node.text) sr1:= node.selectSingleNode('.//Lieferanschrift/Ort').text sr1:= sr1 + node.selectSingleNode('.//Lieferanschrift/Strasse').text sr2:= node.selectSingleNode('.//Rechnungsanschrift/Ort').text; sr2:= sr2 + node.selectSingleNode('.//Rechnungsanschrift/Strasse').text; writeln(node.selectSingleNode('.//Auftragskopf/FremdlieferscheinNr').text); Auftrag:= node.selectSingleNode('.//Auftragskopf/FremdlieferscheinNr').text writeln(node.selectSingleNode('.//Auftragskopf/FremdlieferscheinNr').text); if ANSICompareText(sr1, sr2) = 0 then begin
srlist:= FindAllFiles(PDFFILEPATH,'*'+Auftrag+'_??.pdf',true);
for it:= 0 to srlist.count-1 do begin
writeln((srlist.strings[it]));
if lCopyFile(srlist.strings[it],
PDFEXPORT+extractfilename(srlist.strings[it]),true)
then writeln('copyof=: '+srlist.strings[it]);
end;
srlist.free;
srlist:= Nil;
it:=0;
result:= true;
end else begin
srlist:= FindAllFiles(PDFFILEPATH,'*'+Auftrag+'*.pdf',true);
for it:= 0 to srlist.count-1 do begin
if lCopyFile(srlist.strings[it],
PDFEXPORT+extractfilename(srlist.strings[it]),true)
then writeln('copyof<>: '+srlist.strings[it]);
end;
DeleteFiles(PDFEXPORT, '*RG.pdf');
DeleteFile(PDFEXPORT+'Special_'+Auftrag+'_ES.pdf');
srlist.free;
result:= false
end;
//mk change in op
fileprefix:= 'WAB';
odbcDSN:= 'advance_kmu_loc';
if filePrefix='WAB' then begin
mySQL:= 'UPDATE verk_auftrag SET Status = 61 where Auftrag = '+Auftrag;
writeln('order back: '+
itoa(MySQLQueryExecute2(mysql, odbcDsn, strtoint(Auftrag),true)));
end;
if filePrefix='WEA' then begin
mySQL:= 'UPDATE verk_auftrag SET Status = 52 where Auftrag = '+Auftrag;
writeln('order back: '+
itoa(MySQLQueryExecute2(mysql, odbcDsn, strtoint(Auftrag),true)));
end;
nodes_se:= node.selectNodes('.//Auftragspositionen/Position');
writeln('total posnod: '+itoa(nodes_se.length))
for i:= 0 to nodes_se.length - 1 do begin
node:= nodes_se.item[i];
writeln('Posit=' + node.text);
end;//
writeln('------------------------');
end; //
except
writeln(exceptiontoString(exceptiontype, exceptionparam))
finally
xml:= unassigned;
xml:= NULL;
end;
end;
【讨论】:
嗨,Max,您能否提供一些有用的提示,说明此代码在做什么而 OP 的代码没有?为什么这是正确的,而他们的代码却不是?它的工作方式有什么不同?提前致谢。 该代码从基于 XML 的数据集包(客户端数据集)中解析一些日期,复制一些 pdf 文件并在此基础上更新另一个数据集。两个代码都是正确的。【参考方案2】:这是因为您在 XPath 中使用了“//”语法。该特定语法选择文档中名为 that 的第一个节点。尝试查看 https://www.w3schools.com/xml/xpath_syntax.asp 以获取有关 XPath 语法的信息。
如果您要查找子节点,请尝试仅使用节点名称(即:'Job_Owner' 而不是 '//Job_Owner')
【讨论】:
好吧,这行得通...我知道那个语法,但听起来很合理,如果node
不包含所有文档,那么该语法不会搜索所有文档,但会只在node
代表的代码内搜索
不是最好的使用方法 // 因为它会在不同级别上有多个 Job_Owner 的情况下给出不正确的值,因为它会返回任何 Job_Owner 的第一次出现。更好的方法是使用 ./Job_Owner,因为它会相对于当前节点进行搜索。
所以重点是,如果您以 / 或 // 开始查询,那么您在哪个节点上调用 SelectSingleNode()
实际上并不重要?
我实际上只是在阅读 w3schools 页面。虽然它教了如何形成 XPath 查询,但它没有解决这个问题,因为它没有提到将查询用作 SelectSingleNode()
等在特定节点对象上调用的方法的参数。
如果您将命名空间添加到根元素,这将再次中断并重现 OP 提到的行为,即使使用原始节点名称或 './nodeName' - selectsinglenode 将返回 null 每个时间【参考方案3】:
Infernex87 是正确的,Job_Owner
在这种情况下简单有效。但是,如果它不是直接孩子,您可以这样做:
.//Job_Owner
就像目录一样,.
是当前节点,所以这会查找当前节点的后代,而不是文档的根。
【讨论】:
我认为应该明确指出(不仅仅是暗示),SelectNodes() 和 SelectSingleNode() 方法可以访问整个 XML 文档,并且需要使用“./”锚定才能按预期工作.使用“./Job_Owner”在当前上下文位置根。【参考方案4】:Infernex87 找到了原因。通过您的 XML,我想走 LINQ 路线对您来说可能是一个不错的选择。如果您想开始,Scott Gu's blog 是一个很好的资源。
【讨论】:
是的,我尝试搜索一点 LINQ to XML,但我还没有找到任何实用的东西(尽管我认为我搜索得不够多!)。感谢您的提示!以上是关于C# 中 XmlNode.SelectSingleNode(string xpath) 的正确用法是啥?的主要内容,如果未能解决你的问题,请参考以下文章