如何使用MSXML查询默认名称空间



我有一些XML:

<?xml version="1.0" ?>
<Project ToolsVersion="4.0">
    <PropertyGroup Condition="'$(key)'=='1111'">
          <Key>Value</Key>
    </PropertyGroup>
</Project>

注意:这不是我实际使用的XML,它只是更漂亮,更短,并说明了问题。

使用MSXML我可以查询节点:

IXMLDOMNode node = doc.selectSingleNode("//PropertyGroup/@Condition");

它运行良好:

条件= " $(关键)的= = 1111"

但这不是真正的XML,我有

实际上,我拥有的XML包含一个名称空间声明:

xmlns = " http://schemas.microsoft.com/developer/msbuild/2003 "

使成为实际的 XML文档:

<?xml version="1.0" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup Condition="'$(key)'=='1111'">
          <Key>Value</Key>
    </PropertyGroup>
</Project>

现在我的查询:

IDOMNode node = doc.selectSingleNode("//PropertyGroup/@Condition");

返回不匹配的节点。

如何使用MSXML查询默认命名空间?

注意:

  • 我已经知道如何查询非默认命名空间在xml;你使用:

       doc.setProperty("SelectionNamespaces", 
             "xmlns="http://schemas.microsoft.com/developer/msbuild/2003");
    
  • 我已经知道如何查询。net中的默认命名空间。你使用命名空间管理器,给默认命名空间一个名字,然后用这个名字查询,然后你可以查询非默认命名空间因为它不再是默认的

  • i 可以从我收到的XML字符串中删除冒犯的xmlns文本,但我宁愿"以正确的方式做"

如何使用MSXML查询"default""unnamed"命名空间?


注意:实际上我使用的是SQL Server的XML ShowPlan输出:

<?xml version="1.0" encoding="UTF-16" standalone="yes"?>
   <ShowPlanXML Version="1.1" Build="10.50.1600.1" 
                   xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
      <BatchSequence>
           <Batch>
           ...
           </Batch>
      </BatchSequence>
   </ShowPlanXML> 

您可以再次看到违规的名称空间声明。删除它是可行的,但这很繁琐。

你还试过什么?

我也尝试设置选择命名空间:

doc.setProperty('SelectionNamespaces', 
      'xmlns="http://schemas.microsoft.com/developer/msbuild/2003"');

正如微软在一篇知识库文章中所暗示的那样。

i 如何获得默认命名空间?

实际上,我不关心名称空间。我的问题是有意义的,我希望它工作。因此,这个问题的另一种方法可能是:

如何查询默认的命名空间是否,以及该命名空间的名称是(或不是)?

注意: msxml是原生代码,并且在本地Win32编译器(即没有。net框架或CLR)中使用

在将名称空间添加到SelectionNamespaces时显式地为其提供缩写别名:

doc.setProperty("SelectionNamespaces",
      "xmlns:peanut='http://schemas.microsoft.com/developer/msbuild/2003'");

,然后使用该名称空间查询(但通过其缩写别名引用):

IDOMNode node = doc.selectSingleNode("//peanut:PropertyGroup/@Condition");

您可以为该名称空间提供任何您想要的缩写别名(这里我使用peanut的值来演示它可以是您想要的缩写别名的值)。
然后在"搜索条件"中使用相同的缩写别名作为前缀(在本例中为peanut:PropertyGroup)。

<标题>建议早些时候h1> 会尝试移动到Xml.Linq

下面是一个示例(带有名称空间)。

      try
    {
        XDocument xDoc1 = XDocument.Parse("<?xml version="1.0" ?><Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><PropertyGroup Condition="'$(key)'=='1111'"><Key>Value</Key></PropertyGroup></Project>");
        XNamespace ns1 = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
        var list1 = from list in xDoc1.Descendants(ns1 + "Project")
                    from item in list.Elements(ns1 + "PropertyGroup")
                    /* where item.Element(ns + "HintPath") != null */
                    where item.Attribute("Condition") != null
                    select new
                    {
                        MyCondition = item.Attribute("Condition") == null ? "Not Here!" : item.Attribute("Condition").Value,
                        MyFake = item.Attribute("DoesNotExistTest") == null ? "Not Here Sucker!" : item.Attribute("DoesNotExistTest").Value
                    };

        foreach (var v in list1)
        {
            Console.WriteLine(v.ToString());
        }

        XDocument xDoc2 = XDocument.Parse("<?xml version="1.0" encoding="UTF-16" standalone="yes"?>   <ShowPlanXML Version="1.1" Build="10.50.1600.1"                    xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">      <BatchSequence>            <Batch>Something I Threw In Here</Batch>      </BatchSequence>    </ShowPlanXML> ");
        XNamespace ns2 = XNamespace.Get("http://schemas.microsoft.com/sqlserver/2004/07/showplan");
        var list2 = from list in xDoc2.Descendants(ns2 + "ShowPlanXML")
                    from item in list.Elements(ns2 + "BatchSequence")
                    /*                             where item.Attribute("Condition") != null */
                    where item.Element(ns2 + "Batch") != null 
                    select new
                    {
                        BatchValue = (item.Element(ns2 + "Batch") == null) ? string.Empty : item.Element(ns2 + "Batch").Value
                    };

        foreach (var v in list2)
        {
            Console.WriteLine(v.ToString());
        }

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

如果您像我一样,并且不想更改您的.SelectNodes("//Test")代码以匹配每个可能的名称空间,您可以参考我的回答如何忽略XML名称空间

基本上,我像这样使用.transformNodeToObject 方法:
Public Sub fixNS(ByRef doc As DOMDocument60)
  ' Create a new XML document (fixNS0) that contains an XSLT style sheet.
  ' The XSLT style sheet will remove namespace prefixes from XML elements and attributes.
  ' The resulting XML document will have the same content as the original, but with the namespace prefixes removed.
  Dim fixNS0 As New DOMDocument60
  fixNS0.LoadXML ("<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" & _
    "<xsl:output method='xml' indent='yes' omit-xml-declaration='yes' />" & _
    "<xsl:template match='comment()'> <xsl:copy/> </xsl:template>" & _
    "<xsl:template match='*'>" & _
      "<xsl:text>&#xA;</xsl:text>" & _
      "<xsl:element name='{local-name(.)}'> <xsl:apply-templates select='@* | node()'/> </xsl:element>" & _
      "<xsl:text>&#xA;</xsl:text>" & _
    "</xsl:template> <xsl:template match='@*'>" & _
      "<xsl:attribute name='{local-name(.)}'> <xsl:value-of select='.'/> </xsl:attribute>" & _
    "</xsl:template> </xsl:stylesheet>")
  ' Apply the XSLT style sheet (in fixNS0) to the XML document (in doc).
  ' The result of the transformation is written back to the same XML document (in doc).
  doc.transformNodeToObject fixNS0, doc
End Sub

最新更新