2012-09-26 11 views
11

Sto cercando di analizzare un documento XML. Il documento in questione è un file AppxManifest.Impossibile ottenere XmlDocument.SelectNodes per recuperare uno dei miei nodi?

Un esempio documento si presenta così:

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

cerco di analizzare in questo modo:

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

Tuttavia, dopo eseguo questo, nodes sarà mai contenere qualsiasi cosa. Il documento xml è caricato e tale però. utilizzando SelectNodes("//*") restituisce ogni nodo come previsto. Qual è il mio problema qui?

Ho anche provato molte variazioni su quella query XPath come

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

Nulla sembra recuperare il singolo nodo però. Idealmente, mi piacerebbe che i nodi contengano tutti i nodi Application

+2

Il titolo parla di XDocument, ma il codice utilizza XmlDocument. Se tu fossi * veramente * usando LINQ in XML, ti suggerirei semplicemente di usare Descendants ... LINQ to XML è un'opzione? –

+0

@JonSkeet purtroppo non possiamo usare Linq in XML perché miriamo a .Net 2.0. Comunque volevo mettere XmlDocument. Ricevo sempre i due confusi – Earlz

risposta

27

È necessario utilizzare lo spazio dei nomi xml appositamente per selezionarli. considerare

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

nel tuo caso questo codice può anche funzionare bene:

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

Per il primo si ottiene "espressione deve valutare su un nodo-set" – Earlz

+0

campione aggiornato - mancava * – aiodintsov

+0

Ah, che funziona ora. Per caso c'è un modo più pulito per farlo? Non mi sono mai occupato di namespace con XPath quindi sono abituato a qualcosa di semplice e pulito come '/ Applications/Application' appena funzionante – Earlz

2

Potrebbe essere necessario leggere questo

Ecco il codice:

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

Ho letto che :) Non mi ero reso conto che avrebbe cambiato la mia query XPath in modo così radicale rispetto a un file XML senza uno spazio dei nomi – Earlz

7

È necessario specificare i prefissi per gli spazi dei nomi in NamespaceManager e XPaths. Nota che i prefissi non devono necessariamente corrispondere a nulla tranne che tra XPath e il tuo gestore dello spazio dei nomi *.

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

E come indicato da altre risposte XPath che accetta qualsiasi spazio dei nomi è un'altra opzione.

*) I.e. nel tuo campione particolare ci sono 2 namespace "default" (nota che il prefisso predefinito non è lo stesso del namespace vuoto) e "build". Pertanto, quando si definisce il gestore dello spazio dei nomi, è necessario specificare un prefisso per ciascuno spazio dei nomi (se è necessario indirizzare i nodi in entrambi), ma i prefissi possono essere stringhe arbitrarie (validi per i prefissi ma non vuoti). Cioè usa "a" per lo spazio dei nomi "predefinito" e "barra" per lo spazio dei nomi mappato a "build" nell'XML.

+0

Heh, è ​​strano. Con quel codice ricevo "Namespace Manager o XsltContext necessari." Questa query ha un prefisso, una variabile o una funzione definita dall'utente "che non ha senso per me dato che ho un gestore di namespace? – Earlz

+1

Penso che sia "// a: Applicazioni" o "a: Pacchetto/a: Applicazioni", perché quel nodo non è direttamente sotto la radice. – MiMo

+1

Il gestore dello spazio dei nomi deve essere passato a 'SelectNodes':' SelectNodes ("// a: Applications", mgr); ' – MiMo

0

Non in questo caso particolare, ma in generale, se lo spazio dei nomi URN nell'XML effettivo non è esattamente uguale a quello utilizzato per aggiungere uno spazio dei nomi a un gestore di spazi dei nomi (ad esempio manca una barra finale) e un prefisso è specificato in XPath, la query può restituire null.

Se URN namespace in XML non è affidabile, la sintassi

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

funzionerà.

Problemi correlati