Пространство имен XElement по умолчанию для атрибутов обеспечивает неожиданное поведение.
-
22-07-2019 - |
Вопрос
У меня возникли проблемы с созданием XML-документа, содержащего пространство имен по умолчанию и именованное пространство имен. Трудно объяснить, проще просто показать, что я пытаюсь создать...
<Root xmlns="http://www.adventure-works.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.SomeLocatation.Com/MySchemaDoc.xsd">
<Book title="Enders Game" author="Orson Scott Card" />
<Book title="I Robot" author="Isaac Asimov" />
</Root>
но в итоге я получаю вот это...
<Root xmlns="http://www.adventure-works.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.SomeLocatation.Com/MySchemaDoc.xsd">
<Book p3:title="Enders Game" p3:author="Orson Scott Card" xmlns:p3="http://www.adventure-works.com" />
<Book p3:title="I Robot" p3:author="Isaac Asimov" xmlns:p3="http://www.adventure-works.com" />
</Root>
Код, который я написал для создания этого фрагмента XML, таков...
XNamespace aw = "http://www.adventure-works.com";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XElement root = new XElement(aw + "Root",
new XAttribute("xmlns", "http://www.adventure-works.com"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
new XAttribute(xsi + "SchemaLocation", "http://www.SomeLocatation.Com/MySchemaDoc.xsd"),
new XElement(aw + "Book",
new XAttribute(aw + "title", "Enders Game"),
new XAttribute(aw + "author", "Orson Scott Card")),
new XElement(aw + "Book",
new XAttribute(aw + "title", "I Robot"),
new XAttribute(aw + "author", "Isaac Asimov")));
на основе пример в MSDN
****РЕДАКТИРОВАТЬ****
Хорошо, после еще нескольких экспериментов я теперь очень запутался в том, как работают пространства имен XML....
если я удалю атрибут aw + theattribute, я получу то, что мне нужно... но теперь кажется, что то, что мне нужно, на самом деле не то, что я ожидал.Я думал, что пространства имен унаследованы от своих родителей, разве это не относится и к атрибутам?потому что этот код для чтения атрибутов работает не так, как я ожидал...
XElement xe = XElement.Parse(textBox1.Text);
XNamespace aw = "http://www.adventure-works.com";
var qry = from x in xe.Descendants(aw + "Book")
select (string)x.Attribute(aw + "author");
Однако, если я удалю aw + в атрибуте, все будет в порядке, и я предположу, что у меня не может быть атрибутов в пространстве имен по умолчанию.Это верно?
Решение
Хороший вопрос.Я немного покопался и нашел этот фрагмент спецификации XML:
Объявление пространства имен по умолчанию применяется ко всем непреднамеренным именам элементов в его объеме.Объявления пространства имен по умолчанию не применяются непосредственно к именам атрибутов;Интерпретация неподвижных атрибутов определяется элементом, на котором они появляются.
Позже он приводит следующий пример:
Например, каждый из плохих тегов пустого элемента недопустим в следующем:
<!-- http://www.w3.org is bound to n1 and n2 -->
<x xmlns:n1="http://www.w3.org"
xmlns:n2="http://www.w3.org" >
<bad a="1" a="2" />
<bad n1:a="1" n2:a="2" />
</x>
Однако каждое из следующих действий допустимо, второе — потому, что пространство имен по умолчанию не применяется к именам атрибутов:
<!-- http://www.w3.org is bound to n1 and is the default -->
<x xmlns:n1="http://www.w3.org"
xmlns="http://www.w3.org" >
<good a="1" b="2" />
<good a="1" n1:a="2" />
</x>
В общем, похоже, что имена атрибутов по умолчанию не имеют пространств имен, что объясняет все, что вы видели :)
Другие советы
XElement doc = XElement.Parse(ToXml());
doc.DescendantsAndSelf().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
var ele = doc.DescendantsAndSelf();
foreach (var el in ele)
el.Name = ns != null ? ns + el.Name.LocalName : el.Name.LocalName;
Для всех, кто потратил 2 дня, пытаясь найти ответ.