Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't get XmlDocument.SelectNodes to retrieve any of my nodes?

I'm trying to parse an XML document. The document in question is an AppxManifest file.

An example document looks like this:

<?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>

I try to parse it like so:

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

However, after I execute this, nodes will never contain anything. The xml document is loaded and such though. using SelectNodes("//*") returns every node as expected. What is my problem here?

I've also tried many variations on that XPath query such as

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

Nothing appears to retrieve the single node though. Ideally, I'd like for nodes to contain all of the Application nodes

like image 632
Earlz Avatar asked Sep 26 '12 18:09

Earlz


People also ask

What is the difference between XmlDocument and XDocument?

XDocument is from the LINQ to XML API, and XmlDocument is the standard DOM-style API for XML. If you know DOM well, and don't want to learn LINQ to XML, go with XmlDocument . If you're new to both, check out this page that compares the two, and pick which one you like the looks of better.

What is XmlNodeList?

XmlNodeList supports iteration and indexed access. XmlNodeList is returned by the following properties and methods. XmlNode. ChildNodes - Returns an XmlNodeList containing all the children of the node. XmlNode.


2 Answers

You have to use xml namespace specifically to select them. consider

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

in your case this code may also work well:

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);
like image 111
aiodintsov Avatar answered Oct 13 '22 01:10

aiodintsov


You need to specify prefixes for namespaces in NamespaceManager and XPaths. Note that prefixes does not need to match anything except between your XPath and your namespace manager*.

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);

And as pointed out by other answers XPath that accepts any namespace is another option.

*) I.e. in your particular sample there are 2 namespaces "default" (note that default prefix is not the same as empty namespace) and "build". So when you define your namespace manager you need to specify a prefix for each of the namespace (if you need to target nodes in both), but prefixes can be arbitrary strings (valid for prefixes but not empty). I.e. use "a" for "default" namespace and "bar" for namespace that mapped to "build" in the XML.

like image 44
Alexei Levenkov Avatar answered Oct 13 '22 00:10

Alexei Levenkov