Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么NamespaceManager在XPath中不使用前缀时不使用DefaultNamespace_C#_.net_Xml_Xpath_Xml Namespaces - Fatal编程技术网

C# 为什么NamespaceManager在XPath中不使用前缀时不使用DefaultNamespace

C# 为什么NamespaceManager在XPath中不使用前缀时不使用DefaultNamespace,c#,.net,xml,xpath,xml-namespaces,C#,.net,Xml,Xpath,Xml Namespaces,当我想使用XPath遍历XmlDocument时,我遇到了一个问题,文档中有许多丑陋的名称空间,因此我开始使用NamespaceManager和XPath XML如下所示 <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:exce

当我想使用XPath遍历XmlDocument时,我遇到了一个问题,文档中有许多丑陋的名称空间,因此我开始使用
NamespaceManager
和XPath

XML如下所示

<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:x="urn:schemas-microsoft-com:office:excel"
 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:html="http://www.w3.org/TR/REC-html40">
    <Worksheet ss:Name="KA0100401">
        <Table>
            <Row>
                <Cell>Data</Cell>
            </Row>
            <!-- more rows... -->
        </Table>
    </Worksheet>
    <Worksheet ss:Name="KA0100402">
        <!-- .... --->
    </Worksheet>
</Workbook>
但是,当我尝试访问一个节点时

foreach (XmlNode row in document.SelectNodes("/Workbook/Worksheet[1]/Table/Row", manager))
我从来没有得到任何结果。我的印象是,通过使用空前缀设置第一个名称空间,在该工作区中搜索节点时就不需要设置该名称空间

但事实上:

如果XPath表达式不包含前缀,则假定命名空间统一资源标识符(URI)是空命名空间

为什么呢?更重要的是:如果不使用前缀将节点设置为空名称空间,如何访问默认名称空间中的节点

如果在搜索节点时无法访问管理器,那么在管理器上设置默认名称空间有什么好处?

来自:

节点测试中的QName使用表达式上下文中的命名空间声明扩展为扩展名称这与在开始和结束标记中对元素类型名称进行扩展的方式相同,只是没有使用用xmlns声明的默认名称空间:如果QName没有前缀,则名称空间URI为null(这与扩展属性名称的方式相同).如果QName的前缀在表达式上下文中没有名称空间声明,则为错误

因此,这不是关于
NamespaceManager
的问题,而是XPath的定义方式


您缺少的一点是,您在
NamespaceManager
中使用的前缀不必与XML文档中的前缀类似。如果需要,您可以使用
xcel
前缀作为
urn:schemas microsoft com:office:excel
,使用
sp
前缀作为
urn:schemas microsoft com:office:spreadsheet
。事实上,您已经在名称空间管理器中为该URN分配了前缀,因此您可以使用该前缀:

foreach (XmlNode row in 
       document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row", manager))

关于这个问题:

如果我在搜索节点时甚至无法访问管理器,那么在管理器上设置默认名称空间有什么好处


好处是
XmlNamespaceManager
不仅仅用于评估XPath。例如,它可以用来跟踪XML文档中的名称空间,其中有一个默认名称空间的概念。

我无法回答您的最后一个问题(“什么是好的…”),除非它在非XPath情况下有帮助。但是关于“如果不使用前缀,如何访问默认名称空间中的节点将它们设置为空名称空间?”的问题,答案是必须使用前缀

因此,在本例中,由于您将前缀
ss
声明为绑定到URI为
urn:schemas microsoft com:office:spreadsheet
的命名空间,该命名空间与默认命名空间相同,因此您可以在XPath表达式中使用
ss
前缀:

foreach (XmlNode row in document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row",
  manager))

@JLRishe的答案对于访问默认名称空间中的节点是正确的(即始终将前缀映射到
XmlNamespaceManager
中的默认名称空间)

从quote()读取链接的整个上下文可以看出,XPath表达式中没有使用默认的“empty”前缀

前缀 类型:System.String

与要添加的命名空间关联的前缀。使用String.Empty添加默认命名空间。>

注意如果XmlNamespaceManager将用于解析XML路径语言(XPath)表达式中的名称空间,则必须指定前缀。如果XPath表达式不包含前缀,则假定命名空间统一资源标识符(URI)是空命名空间。有关XPath表达式和XmlNamespaceManager的更多信息,请参阅XmlNode.SelectNodes和XPathExpression.SetContext方法


我发现如果删除默认名称空间


xmlns=“urn:schemas microsoft com:office:spreadsheet”“什么是好的…”-难道您没有想到,
XmlNamespaceManager
被更多的代码使用,而不仅仅是用于XPath查询,在这些情况下,默认名称空间可能非常有用吗?可能重复:@Damien:不必粗鲁。@LarsH-这是一种修辞手段。我很抱歉你觉得这很粗鲁,我经常用这种评论方式让人们质疑他们的假设,这是第一次有人断言这是粗鲁的。很抱歉,这冒犯了你。评论不错,因为;是的,事实上是这样。我不知道这位经理还有什么其他的应用程序。@Damien:谢谢你对反馈持开放态度。
foreach (XmlNode row in document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row",
  manager))
public static string XPathAddDeafultNameSpaceProccess(this string XPathProcess)
        {
            string[] XPSplit = XPathProcess.Split('/');

            for (int i = 0; i < XPSplit.Length; i++)//if element no namespace, add default
            {
                if (!XPSplit[i].Contains(':') && !XPSplit[i].Contains('@'))
                    XPSplit[i] = "default:" + XPSplit[i];
            }
            for (int i = 0; i < XPSplit.Length; i++)
            {
                if (i != XPSplit.Length - 1)//if not the last, add"/"                       
                XPSplit[i] += "/";
            }

            string output = "";
            foreach (string s in XPSplit)//combine
                output += s;
            return output;
        }