2010-10-20 5 views
7

J'essaie d'analyser des documents XML standard qui utilisent un schéma appelé MARCXML provenant de diverses sources.Comment analyser correctement un document XML avec des espaces de noms arbitraires

Voici les premières lignes d'un fichier XML exemple qui doit être manipulé ...

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

et un sans préfixe d'espace de nom ...

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

Point clé: Afin de résoudre les XPaths plus loin dans le programme, je dois passer par une routine regex pour ajouter les namespaces au NameTable (qui ne les ajoute pas par défaut). Cela me semble inutile.

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

L'appel XPath ressemble à quelque chose comme ça ...

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

LeaderNode est une valeur configurable et serait égale "marc:leader" dans le premier exemple et "leader" dans le second exemple.

Existe-t-il une meilleure façon de le faire? Note: les suggestions pour résoudre ce problème en utilisant LINQ sont les bienvenues, mais j'aimerais surtout savoir comment résoudre ceci en utilisant XmlDocument.

EDIT: Je a suivi les conseils de GrayWizardx et ont maintenant le code suivant ...

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

Maintenant, il n'y a plus de dépendance à l'égard Regex!

+0

Je fais face presque exactement au même problème. Comment accomplissez-vous votre magie «LeaderNode»? Avez-vous la précognition de quel type d'enregistrement vous avez affaire? –

Répondre

2

Si vous sais il va y avoir un élément donné dans le document (par exemple l'élément racine) vous pouvez essayer d'utiliser GetNamespaceOfPrefix.

+0

Cela semble prometteur. Je vais essayer :) –

+0

La façon dont je comprends les espaces de noms, ils peuvent être déclarés n'importe où dans le document. Pouvez-vous résumer cette méthode assez pour traiter ce cas général? –

+0

@Patrick M Je ne suis pas sûr d'être honnête. Ma compréhension était qu'ils devaient être définis sur l'élément racine du document, mais le probablement pourrait être ajouté à n'importe quel élément parent. Je n'ai pas regardé cela pendant un moment. – GrayWizardx

Questions connexes