【问题标题】:Can't get XmlDocument.SelectNodes to retrieve any of my nodes?无法让 XmlDocument.SelectNodes 检索我的任何节点?
【发布时间】:2012-09-26 18:12:36
【问题描述】:

我正在尝试解析 XML 文档。有问题的文档是一个 AppxManifest 文件。

示例文档如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:build="http://schemas.microsoft.com/developer/appx/2012/build" IgnorableNamespaces="build">
  <Identity Name="uytury" Publisher="hygj" Version="1.0.0.12" ProcessorArchitecture="neutral" />
  <Properties>
    <DisplayName>jhjj</DisplayName>
    <PublisherDisplayName>bhhjb</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
  </Properties>
  <Prerequisites>
    <OSMinVersion>6.2.1</OSMinVersion>
    <OSMaxVersionTested>6.2.1</OSMaxVersionTested>
  </Prerequisites>
  <Resources>
    <Resource Language="EN" />
  </Resources>
  <Applications>
    <Application Id="App" Executable="gfg.exe" EntryPoint="gfg.App">
      <VisualElements DisplayName="fdsf" Logo="Assets\Logo.png" SmallLogo="Assets\SmallLogo.png" Description="gfdsg" ForegroundText="light" BackgroundColor="#2672EC">
        <DefaultTile ShowName="allLogos" WideLogo="Assets\WideLogo.png" ShortName="gfdsg" />
        <SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="#2672EC" />
        <InitialRotationPreference>
          <Rotation Preference="portrait" />
          <Rotation Preference="landscape" />
          <Rotation Preference="portraitFlipped" />
          <Rotation Preference="landscapeFlipped" />
        </InitialRotationPreference>
      </VisualElements>
      <Extensions>
        <Extension Category="windows.search" />
        <Extension Category="windows.shareTarget">
          <ShareTarget>
            <DataFormat>Text</DataFormat>
          </ShareTarget>
        </Extension>
      </Extensions>
    </Application>
  </Applications>
  <build:Metadata>
    <build:Item Name="TargetFrameworkMoniker" Value=".NETCore,Version=v4.5" />
    <build:Item Name="VisualStudio" Version="11.0" />
    <build:Item Name="OperatingSystem" Version="6.2.9200.16384 (win8_rtm.120725-1247)" />
    <build:Item Name="Microsoft.Build.AppxPackage.dll" Version="11.0.50727.1" />
    <build:Item Name="Microsoft.Windows.UI.Xaml.Build.Tasks.dll" Version="11.0.50727.1" />
  </build:Metadata>
</Package>

我尝试像这样解析它:

var xml=new XmlDocument();
xml.Load(myfile);
var mgr=new XmlNamespaceManager(xml.NameTable);
mgr.AddNamespace("", "http://schemas.microsoft.com/appx/2010/manifest");
var nodes=xml.SelectNodes("Applications");

但是,在我执行此操作后,nodes 将永远不会包含任何内容。 xml 文档已加载等。使用SelectNodes("//*") 按预期返回每个节点。我的问题是什么?

我还尝试了该 XPath 查询的许多变体,例如

  • /Package/Applications/Application
  • Applications/Application
  • Applications/*

但似乎没有任何东西可以检索单个节点。理想情况下,我希望节点包含所有 Application 节点

【问题讨论】:

  • 您的标题谈到了 XDocument,但您的代码使用了 XmlDocument。如果您真的使用 LINQ to XML,我只是建议使用 Descendants... LINQ to XML 是一种选择吗?
  • @JonSkeet 遗憾的是我们不能使用 Linq to XML,因为我们的目标是 .Net 2.0。但是我的意思是把 XmlDocument.我总是把这两个弄糊涂

标签: c# .net xml xpath xmldocument


【解决方案1】:

您必须专门使用 xml 命名空间来选择它们。考虑

"//*[local-name()='Applications']/*[local-name()='Application']"    

在您的情况下,此代码也可能运行良好:

var doc = new XmlDocument();
doc.LoadXml(xml);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("a", "http://schemas.microsoft.com/appx/2010/manifest");
var nodes = doc.SelectNodes("//a:Applications/a:Application",nsmgr);

【讨论】:

  • 对于第一个我得到“表达式必须评估为节点集”
  • 啊,现在可以了。碰巧有更清洁的方法吗?我从来没有用 XPath 处理过命名空间,所以我习惯了像 /Applications/Application 这样简单而干净的东西
  • 几个月前我不得不使用它,但找不到更简洁的语法,但 .net 框架系统库不支持 XPath 2.0 "//*:name"。不过,您可以找到第 3 方 XPath 2.0 和 XSTL 2.0 产品。
  • 哦,你可以通过这个重载msdn.microsoft.com/en-us/library/4bektfx9.aspx 指定你需要的命名空间,但是在我的情况下,我确实处理了那些可能声明了不同命名空间/命名空间版本的通用请求,因此解析命名空间不是一个选项我
  • 虽然您经历了很多修改,但我认为您提供了最完整的答案。其他人提到命名命名空间,但您还包括了重载以使其实际工作,并且让我的 XPath 查询变得漂亮和干净 :) 谢谢!
【解决方案2】:

您需要在 NamespaceManager 和 XPaths 中为命名空间指定前缀。请注意,前缀不需要匹配任何内容,除了 XPath 和命名空间管理器*。

var xml=new XmlDocument();
xml.Load(myfile);
var mgr=new XmlNamespaceManager(xml.NameTable);
mgr.AddNamespace("a", "http://schemas.microsoft.com/appx/2010/manifest");
mgr.AddNamespace("bar", "http://schemas.microsoft.com/developer/appx/2012/build");
var nodes=xml.SelectNodes("//a:Applications", mgr);

正如其他答案所指出的那样,接受任何命名空间的 XPath 是另一种选择。

*) 即在您的特定示例中,有 2 个命名空间“默认”(请注意,默认前缀与空命名空间不同)和“构建”。因此,当您定义命名空间管理器时,您需要为每个命名空间指定一个前缀(如果您需要同时定位两个节点),但前缀可以是任意字符串(对前缀有效但不能为空)。 IE。使用“a”作为“默认”命名空间,使用“bar”作为映射到 XML 中“build”的命名空间。

【讨论】:

  • 嘿,这很奇怪。使用该代码,我得到“需要命名空间管理器或 XsltContext。这个查询有一个前缀、变量或用户定义的函数”,这对我来说没有任何意义,因为我有一个命名空间管理器?
  • 我认为是//a:Applicationsa:Package/a:Applications,因为该节点不在根目录下。
  • 命名空间管理器应该传递给SelectNodes:SelectNodes("//a:Applications", mgr);
  • @Earlz,样本已修复(我希望) - 忘记传递命名空间管理器。并内嵌 MiMo 建议。
【解决方案3】:

不是在这种特殊情况下,但一般情况下,如果实际 XML 中的命名空间 URN 与用于将命名空间添加到命名空间管理器的名称不完全相同(例如:缺少尾部斜杠),并且前缀是在 XPath 中指定,查询可能返回null

如果 XML 中的命名空间 URN 不可靠,语法

"//*[local-name()='tag']" 

会起作用的。

【讨论】:

    【解决方案4】:

    您可能需要阅读此内容

    这是你的代码:

    var xml = new XmlDocument();
    xml.Load("myXMLFile1.xml");
    var mgr = new XmlNamespaceManager(xml.NameTable);
    mgr.AddNamespace("", "http://schemas.microsoft.com/appx/2010/manifest");
    XmlNode root = xml.DocumentElement;
    var nodes = root.SelectNodes("//*[local-name()='Applications']/*[local-name()='Application']");
    

    【讨论】:

    • 我确实读过 :) 我只是没有意识到与没有命名空间的 XML 文件相比,它会如此彻底地改变我的 XPath 查询
    猜你喜欢
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 2017-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多