Разбор XDocument без необходимости задавать пространство имен по умолчанию
У меня есть некоторые данные XML (аналогично приведенному ниже образцу), и я хочу прочитать значения в коде.
Почему я вынужден указать пространство имен по умолчанию для доступа к каждому элементу? Я ожидал, что пространство имен по умолчанию будет использоваться для всех элементов.
Есть ли более логичный способ достижения моей цели?
Пример XML:
<?xml version="1.0" encoding="UTF-8"?>
<ReceiptsBatch xmlns="http://www.secretsonline.gov.uk/secrets">
<MessageHeader>
<MessageID>00000173</MessageID>
<Timestamp>2009-10-28T16:50:01</Timestamp>
<MessageCheck>BX4f+RmNCVCsT5g</MessageCheck>
</MessageHeader>
<Receipts>
<Receipt>
<Status>OK</Status>
</Receipt>
</Receipts>
</ReceiptsBatch>
Код для чтения элементов XML, я после:
XDocument xDoc = XDocument.Load( FileInPath );
XNamespace ns = "http://www.secretsonline.gov.uk/secrets";
XElement MessageCheck = xDoc.Element(ns+ "MessageHeader").Element(ns+"MessageCheck");
XElement MessageBody = xDoc.Element("Receipts");
5 ответов
Теория заключается в том, что значение документа не зависит от выбора пользователем префиксов пространства имен. Пока данные находятся в пространстве имен http://www.secretsonline.gov.uk/secrets, не имеет значения, решит ли автор использовать префикс "s", "секреты", "_x.cafe.babe". "или префикс" null "(то есть делает его пространством имен по умолчанию). Ваше приложение не должно заботиться: важен только URI. Вот почему ваше приложение должно указывать URI.
Как следует из этого ответа, вы можете сделать это, удалив все пространства имен из копии документа в памяти. Я полагаю, что это должно быть сделано только в том случае, если вы знаете, что в результирующем документе не будет конфликтов имен.
/// <summary>
/// Makes parsing easier by removing the need to specify namespaces for every element.
/// </summary>
private static void RemoveNamespaces(XDocument document)
{
var elements = document.Descendants();
elements.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
foreach (var element in elements)
{
element.Name = element.Name.LocalName;
var strippedAttributes =
from originalAttribute in element.Attributes().ToArray()
select (object)new XAttribute(originalAttribute.Name.LocalName, originalAttribute.Value);
//Note that this also strips the attributes' line number information
element.ReplaceAttributes(strippedAttributes.ToArray());
}
}
Вы можете использовать свойство XmlTextReader.Namespaces, чтобы отключить пространства имен при чтении файла XML.
string filePath;
XmlTextReader xReader = new XmlTextReader(filePath);
xReader.Namespaces = false;
XDocument xDoc = XDocument.Load(xReader);
Вот как работает Linq-To-Xml. Вы не можете найти какой-либо элемент, если он не находится в пространстве имен по умолчанию, и то же самое верно и для его потомков. Самый быстрый способ избавиться от пространства имен - это удалить ссылку на пространство имен из вашего исходного XML.
Обратите внимание, что элемент Receipts
также в пространстве имен http://www.secretsonline.gov.uk/secrets
, Итак XNamespace
также потребуется для доступа к элементу:
XElement MessageBody = xDoc.Element(ns + "Receipts");
В качестве альтернативы использованию пространств имен обратите внимание, что вы можете использовать xpath "независимость от пространства имен", используя local-name()
а также namespace-uri()
например,
/*[local-name()='SomeElement' and namespace-uri()='somexmlns']
Если вы опустите namespace-uri
сказуемое:
/*[local-name()='SomeElement']
Будет соответствовать ns1:SomeElement
а также ns2:SomeElement
и т.д. ИМО я бы всегда предпочел XNamespace
где это возможно, и варианты использования для независимого от пространства имен xpath весьма ограничены, например, для анализа определенных элементов в документах с неизвестными схемами (например, в служебной шине), или для анализа наилучших усилий, где пространство имен может измениться (например, будущее, где xmlns
изменения в соответствии с новой версией схемы документа)