2010-10-20 11 views
7

Sto cercando di analizzare documenti XML standard in qualche modo che utilizzano uno schema chiamato MARCXML da varie origini.Come analizzare correttamente un documento XML con spazi dei nomi arbitrari

Ecco le prime righe di un file XML di esempio che deve essere gestita ...

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> 
<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"> 
    <marc:record> 
    <marc:leader>00925njm 22002777a 4500</marc:leader> 

e uno senza prefissi di namespace ...

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> 
<collection xmlns="http://www.loc.gov/MARC21/slim"> 
    <record> 
    <leader>01142cam 2200301 a 4500</leader> 

Punto chiave: per far sì che gli XPath si risolvano ulteriormente nel programma devo passare attraverso una routine regolare per aggiungere gli spazi dei nomi al NameTable (che non li aggiunge per impostazione predefinita). Questo mi sembra non necessario.

Regex xmlNamespace = new Regex("xmlns:(?<PREFIX>[^=]+)=\"(?<URI>[^\"]+)\"", RegexOptions.Compiled); 

XmlDocument xmlDoc = new XmlDocument(); 
xmlDoc.LoadXml(xmlRecord); 
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); 

MatchCollection namespaces = xmlNamespace.Matches(xmlRecord); 
foreach (Match n in namespaces) 
{ 
    nsMgr.AddNamespace(n.Groups["PREFIX"].ToString(), n.Groups["URI"].ToString()); 
} 

La chiamata XPath simile a questa ...

XmlNode leaderNode = xmlDoc.SelectSingleNode(".//" + LeaderNode, nsMgr);

Dove LeaderNode è un valore configurabile e sarebbe uguale "marc:leader" nel primo esempio e "leader" nel secondo esempio.

Esiste un modo migliore, più efficiente per farlo? Nota: i suggerimenti per risolvere questo problema utilizzando LINQ sono i benvenuti, ma vorrei principalmente sapere come risolvere questo problema utilizzando XmlDocument.

EDIT: ho preso il consiglio di GrayWizardx e ora hanno il seguente codice ...

if (LeaderNode.Contains(":")) 
{ 
    string prefix = LeaderNode.Substring(0, LeaderNode.IndexOf(':')); 
    XmlNode root = xmlDoc.FirstChild; 
    string nameSpace = root.GetNamespaceOfPrefix(prefix); 
    nsMgr.AddNamespace(prefix, nameSpace); 
} 

Ora non c'è più dipendenza da Regex!

+0

Sto affrontando quasi lo stesso identico problema. Come realizzi la tua magia 'LeaderNode'? Hai la precognizione di quale tipo di record hai a che fare? –

risposta

2

Se si sa ci sarà un dato elemento nel documento (per esempio l'elemento radice) si potrebbe provare usando GetNamespaceOfPrefix.

+0

Questo sembra promettente. Ci proverò :) –

+0

Nel modo in cui ho capito gli spazi dei nomi, possono essere dichiarati ovunque nel documento. Riesci ad astrarre questo metodo abbastanza per affrontare questo caso generale? –

+0

@Patrick M Non sono sicuro di essere onesto. La mia comprensione era che dovevano essere definiti sull'elemento radice del documento, ma probabilmente si potevano aggiungere a qualsiasi elemento genitore. Non ho guardato questo per un po '. – GrayWizardx

Problemi correlati