2010-10-20 15 views
7

Estoy tratando de analizar documentos XML algo estándar que usan un esquema llamado MARCXML de varias fuentes.Cómo analizar correctamente un documento XML con espacios de nombres arbitrarios

Estas son las primeras líneas de un archivo XML de ejemplo que debe ser manejada ...

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

y otro sin prefijos de espacio de nombres ...

<?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 clave: Para que los XPath se resuelvan aún más en el programa, tengo que pasar por una rutina de expresiones regulares para agregar los espacios de nombres a NameTable (que no los agrega de manera predeterminada). Esto me parece innecesario.

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 llamada XPath se ve algo como esto ...

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

Dónde LeaderNode es un valor configurable y sería igual a "marc:leader" en el primer ejemplo y "leader" en el segundo ejemplo.

¿Existe alguna forma mejor y más eficiente de hacerlo? Nota: sugerencias para resolver esto usando LINQ son bienvenidas, pero principalmente me gustaría saber cómo resolver esto usando XmlDocument.

EDIT: seguí el consejo de GrayWizardx y ahora tienen el siguiente código ...

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

Ahora no hay más dependencia de la expresión regular!

+0

Estoy enfrentando casi el mismo problema. ¿Cómo logras tu magia 'LeaderNode'? ¿Tiene precognición de qué tipo de registro está tratando? –

Respuesta

2

Si sabe que va a ser un elemento dado en el documento (por ejemplo, el elemento raíz) se podría tratar de usar GetNamespaceOfPrefix.

+0

Esto parece prometedor. Lo probaré :) –

+0

La forma en que entiendo los espacios de nombres, se pueden declarar en cualquier parte del documento. ¿Puedes abstraer este método lo suficiente como para lidiar con ese caso general? –

+0

@Patrick M No estoy seguro de ser honesto. Según entendí, tenían que definirse en el elemento raíz del documento, pero probablemente se podría agregar a cualquier elemento padre. No he mirado esto por un tiempo. – GrayWizardx

Cuestiones relacionadas