2010-10-20 4 views
7

Я пытаюсь разобрать несколько стандартных XML-документов, которые используют схему с именем MARCXML из разных источников.Как правильно разобрать XML-документ с произвольными пространствами имен

Вот первые несколько строк примера XML-файла, который должен быть обработан ...

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

и один без префиксов ...

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

Ключевой момент: чтобы получить XPaths для дальнейшего решения в программе, я должен пройти процедуру регулярного выражения, чтобы добавить пространства имен в NameTable (который не добавляет их по умолчанию). Мне это кажется ненужным.

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

вызов XPath выглядит примерно так ...

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

Где LeaderNode конфигурируемый значение и будет равна "marc:leader" в первом примере и "leader" во втором примере.

Есть ли лучший, более эффективный способ сделать это? Примечание. Предложения по его решению с использованием LINQ приветствуются, но в основном я хотел бы знать, как это решить, используя XmlDocument.

EDIT: Я принял совет GrayWizardx и теперь имеют следующий код ...

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

Теперь больше нет зависимости от Regex!

+0

Я столкнулся с почти той же проблемой. Как вы справляетесь с магией «LeaderNode»? Есть ли у вас предвидение какого типа записи вы имеете дело? –

ответ

2

Если вы знаете, в документе будет указан данный элемент (например, корневой элемент), вы можете попробовать использовать GetNamespaceOfPrefix.

+0

Это выглядит многообещающе. Я дам ему попробовать :) –

+0

Как я понимаю пространства имен, они могут быть объявлены в любом месте документа. Можете ли вы абстрагировать этот метод достаточно, чтобы справиться с этим общим случаем? –

+0

@Patrick M Я не уверен быть честным. Я понял, что их нужно определить в корневом элементе документа, но, вероятно, можно добавить к любому родительскому элементу. Я долго не смотрел на это. – GrayWizardx

Смежные вопросы