Не удается получить XmlDocument.SelectNodes для извлечения любого из моих узлов?

Я пытаюсь проанализировать 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("//*") возвращает каждый node, как ожидалось. В чем моя проблема?

Я также пробовал много вариантов этого запроса XPath, например

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

Как ни странно, ни один node не получает ничего. В идеале я хотел бы, чтобы узлы содержали все узлы Application

Ответ 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);

Ответ 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, который принимает любое пространство имен, является еще одним вариантом.

*) I.e. в вашем конкретном примере есть 2 пространства имен "по умолчанию" (обратите внимание, что префикс по умолчанию не совпадает с пустым пространством имен) и "build". Поэтому, когда вы определяете свой менеджер пространства имен, вам нужно указать префикс для каждого из пространств имен (если вам нужно указывать узлы в обоих), но префиксы могут быть произвольными строками (действительными для префиксов, но не пустыми). То есть используйте "a" для пространства имен "default" и "bar" для пространства имен, которое отображается в "build" в XML.

Ответ 3

Вам может потребоваться прочитать это

Вот ваш код:

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']");

Ответ 4

Не в этом конкретном случае, но в общем случае, если пространство имен URN в фактическом XML не совсем совпадает с тем, которое используется для добавления пространства имен в диспетчер пространства имен (пример: отсутствует конечная косая черта), а префикс - указанный в XPath, запрос может вернуться null.

Если пространство имен URN в XML не является надежным, синтаксис

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

будет работать.