当前位置:  开发笔记 > 编程语言 > 正文

在C#中使用带有默认命名空间的Xpath

如何解决《在C#中使用带有默认命名空间的Xpath》经验,为你挑选了8个好方法。

我有一个带有默认命名空间的XML文档.我正在使用XPathNavigator使用Xpath选择一组节点,如下所示:

XmlElement myXML = ...;  
XPathNavigator navigator = myXML.CreateNavigator();
XPathNodeIterator result = navigator.Select("/outerelement/innerelement");

我没有得到任何结果:我假设这是因为我没有指定命名空间.如何在我的选择中包含命名空间?



1> Marc Gravell..:

首先 - 你不需要导航仪; SelectNodes/SelectSingleNode应该足够了.

但是,您可能需要命名空间管理器 - 例如:

XmlElement el = ...; //TODO
XmlNamespaceManager nsmgr = new XmlNamespaceManager(
    el.OwnerDocument.NameTable);
nsmgr.AddNamespace("x", el.OwnerDocument.DocumentElement.NamespaceURI);
var nodes = el.SelectNodes(@"/x:outerelement/x:innerelement", nsmgr);


注意:将别名设置为空字符串(`nsmgr.AddNamespace("",el.OwnerDocument.DocumentElement.NamespaceURI);`)使其成为默认命名空间.但是,遗憾的是,这并不意味着您可以在不使用前缀的情况下使用XPath(例如`var nodes = el.SelectNodes(@"/ outerelement/innerelement",nsmgr);`).只有你可以使用`nsmgr.DefaultNamespace`看到这个.更多信息:http://stackoverflow.com/a/4271875/361842.如果要避免使用前缀,添加注释以节省其他时间; 即你不能.

2> Cheeso..:

您可能想尝试使用XPath Visualizer工具来帮助您完成.

XPathVisualizer是免费的,易于使用.

替代文字

重要说明:如果您使用的是Windows 7/8但未看到"文件","编辑"和"帮助菜单"项,请按ALT键.



3> Mitselplik..:

对于那些寻找快速入侵解决方案的人来说,特别是在你知道 XML并且不需要担心命名空间的情况下,你可以通过简单地将文件读取到一个字符串来解决这个烦人的小"功能".取代令人反感的属性:

XmlDocument doc = new XmlDocument();
string fileData = File.ReadAllText(fileName);
fileData = fileData.Replace(" xmlns=\"", " whocares=\"");
using (StringReader sr = new StringReader(fileData))
{
   doc.Load(sr);
}

XmlNodeList nodeList = doc.SelectNodes("project/property");

我发现这比在处理单个文件时需要默认命名空间的前缀的所有其他非意义更容易.希望这可以帮助.


这太棒了.关于处理XmlNamespaceManager的所有其他BS都是无用的.10,000个中的9999个你知道XML.
@杰拉德-我不是想让别人知道。我的帖子与KISS有关,而不是嘲笑。无论如何:(1)我称我的解决方案为hack,这暗示它不是“正确”的方法;(2)无论我的听众是否控制XML,我都明确指出,这仅是在了解XML且无需担心名称空间的情况下才是好的解决方案。(3)确实可能只需要几条额外的行就可以包含一个管理器并指定名称空间,但是XPath字符串本身最终看起来确实很混乱,所有额外的名称空间杂乱无章。

4> Tomek Szpako..:

在具有命名空间的XML上使用.NET中的XPath(通过导航器或SelectNodes/SelectSingleNode)时,您需要:

提供您自己的XmlNamespaceManager

显式地在XPath表达式中添加所有元素,这些元素位于命名空间中.

后者是(从下面链接的MS源转述):因为XPath 1.0忽略默认命名空间规范(xmlns ="some_namespace").因此,当您使用不带前缀的元素名称时,它假定为null namespace.

这就是为什么.NET实现XPath忽略了XmlNamespaceManager中前缀为String.Empty的命名空间,并且总是使用null命名空间.

有关详细信息,请参阅XmlNamespaceManager和UndefinedXsltContext不处理默认命名空间.

我发现这个"功能"非常不方便,因为你不能通过简单地添加默认命名空间声明来使旧的XPath命名空间感知,但这就是它的工作原理.



5> 小智..:

您可以在不使用XmlNamespaceManager的情况下使用XPath语句,如下所示:

...
navigator.Select("//*[ local-name() = 'innerelement' and namespace-uri() = '' ]")
...

这是在XML中选择默认命名空间的元素的简单方法.

重点是使用:

namespace-uri() = ''

这将找到具有默认命名空间的元素而不使用前缀.



6> Kent..:

我的回答扩展了布兰登之前的回答.我用他的例子创建了一个扩展方法,如下所示:

static public class XmlDocumentExt
{
    static public XmlNamespaceManager GetPopulatedNamespaceMgr(this System.Xml.XmlDocument xd)
    {
        XmlNamespaceManager nmsp = new XmlNamespaceManager(xd.NameTable);
        XPathNavigator nav = xd.DocumentElement.CreateNavigator();
        foreach (KeyValuePair kvp in nav.GetNamespacesInScope(XmlNamespaceScope.All))
        {
            string sKey = kvp.Key;
            if (sKey == "")
            {
                sKey = "default";
            }
            nmsp.AddNamespace(sKey, kvp.Value);
        }

        return nmsp;
    }
}

然后在我的XML解析代码中,我只添加一行:

XmlDocument xdCandidate = new XmlDocument();
xdCandidate.Load(sCandidateFile);
XmlNamespaceManager nmsp = xdCandidate.GetPopulatedNamespaceMgr();  // 1-line addition
XmlElement xeScoreData = (XmlElement)xdCandidate.SelectSingleNode("default:ScoreData", nmsp);

我非常喜欢这种方法,因为它在从源XML文件加载命名空间方面是完全动态的,并且它并没有完全忽略XML命名空间的概念,因此这可以与需要多个命名空间的XML一起用于解除冲突.



7> Rashmi Pandi..:

如果名称空间因outerelement和innerelement而异

XmlNamespaceManager manager = new XmlNamespaceManager(myXmlDocument.NameTable);
                            manager.AddNamespace("o", "namespaceforOuterElement");
                            manager.AddNamespace("i", "namespaceforInnerElement");
string xpath = @"/o:outerelement/i:innerelement"
// For single node value selection
XPathExpression xPathExpression = navigator.Compile(xpath );
string reportID = myXmlDocument.SelectSingleNode(xPathExpression.Expression, manager).InnerText;

// For multiple node selection
XmlNodeList myNodeList= myXmlDocument.SelectNodes(xpath, manager);



8> Brandon..:

我遇到了类似的空白默认命名空间问题.在这个示例XML中,我有一些带有名称空间前缀的元素和一个没有的单个元素(DataBlock):


 
  
   7
  
  
   Value
   
   
    Value
   
  
 

我试图使用在XPath Visualizer中工作的XPath,但在我的代码中不起作用:

  XmlDocument doc = new XmlDocument();
  doc.Load( textBox1.Text );
  XPathNavigator nav = doc.DocumentElement.CreateNavigator();
  XmlNamespaceManager nsman = new XmlNamespaceManager( nav.NameTable );
  foreach ( KeyValuePair nskvp in nav.GetNamespacesInScope( XmlNamespaceScope.All ) ) {
    nsman.AddNamespace( nskvp.Key, nskvp.Value );
  }

  XPathNodeIterator nodes;

  XPathExpression failingexpr = XPathExpression.Compile( "/src:SRCExample/DataBlock/a:DocID/a:IdID" );
  failingexpr.SetContext( nsman );
  nodes = nav.Select( failingexpr );
  while ( nodes.MoveNext() ) {
    string testvalue = nodes.Current.Value;
  }

我将其缩小到XPath的"DataBlock"元素,但除了通配简单的DataBlock元素之外无法使其工作:

  XPathExpression workingexpr = XPathExpression.Compile( "/src:SRCExample/*/a:DocID/a:IdID" );
  failingexpr.SetContext( nsman );
  nodes = nav.Select( failingexpr );
  while ( nodes.MoveNext() ) {
    string testvalue = nodes.Current.Value;
  }

经过大量的头部搜索和谷歌搜索(让我来到这里)后,我决定直接在我的XmlNamespaceManager加载器中处理默认命名空间,方法是将其更改为:

  foreach ( KeyValuePair nskvp in nav.GetNamespacesInScope( XmlNamespaceScope.All ) ) {
    nsman.AddNamespace( nskvp.Key, nskvp.Value );
    if ( nskvp.Key == "" ) {
      nsman.AddNamespace( "default", nskvp.Value );
    }
  }

所以现在"默认"和""指向相同的命名空间.一旦我这样做,XPath"/ src:SRCExample/default:DataBlock/a:DocID/a:IdID"就像我想要的那样返回了我的结果.希望这有助于澄清其他人的问题.

推荐阅读
linjiabin43
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有