Як запобігти порожнім атрибутам xmlns у виході з .NET XmlDocument?


118

При генерації XML з XmlDocument в .NET, пустий xmlnsатрибут з'являється вперше, коли елемент без вбудованого простору імен вставляється; як це можна запобігти?

Приклад:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root",
    "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner"));
Console.WriteLine(xml.OuterXml);

Вихід:

<root xmlns="whatever:name-space-1.0"><loner xmlns="" /></root>

Бажаний вихід:

<root xmlns="whatever:name-space-1.0"><loner /></root>

Чи є рішення, застосовне до XmlDocumentкоду, а не те, що відбувається після перетворення документа в рядок з OuterXml?

Моє міркування для цього полягає в тому, щоб побачити, чи можу я відповідати стандартному XML певного протоколу за допомогою XMLDocument, створеного XML. Порожній xmlnsатрибут може не зламати або заплутати аналізатор, але він також не присутній у використанні, яке я бачив у цьому протоколі.

Відповіді:


111

Завдяки відповіді Джеремі Лью та ще трохи розібравшись, я зрозумів, як видалити порожні xmlnsатрибути: передайте у простір імен кореневого вузла під час створення будь-якого дочірнього вузла, на якому ви не хочете мати префікса. Використання простору імен без префікса в корені означає, що вам потрібно використовувати той самий простір імен для дочірніх елементів, щоб вони також не мали префіксів.

Фіксований код:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root", "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner", "whatever:name-space-1.0")); 
Console.WriteLine(xml.OuterXml);

Дякую всім за всі ваші відповіді, що привели мене в правильному напрямку!


1
Точно. Якщо помістити елемент <loner> в простір імен "все: ім'я-простір-1.0", це означає, що порожній атрибут xmlns (який не містить простору імен) не буде доданий до нього при його серіалізації. Якщо вам потрібно оновитись,
JeniT

2
Слідкуйте: Елементи потребують цього (або, можливо, краще doc.DocumentElement.NamespaceURI), але не вказуйте простір імен для CreateAttribute()вас, xmlns:psomethingнавіть якщо це той самий урі.
Джейсон Клебан

87

Це варіант відповіді JeniT (Дякую вам дуже сильно!)

XmlElement new_element = doc.CreateElement("Foo", doc.DocumentElement.NamespaceURI);

Це виключає необхідність копіювання або повторення простору імен скрізь.


3
Найкраща відповідь на мою думку. Нам не потрібно знати, що таке область імен за замовчуванням документа (корисно, коли ми не створюємо XML-файл з нуля, тобто в сценаріях читання та зміни).
MuiBienCarlota

11

Якщо <loner>елемент у вашому зразку XML не мав xmlnsдекларації простору імен за замовчуванням на ньому, то він whatever:name-space-1.0знаходився б у просторі імен, а не в просторі імен. Якщо це те, що ви хочете, вам потрібно створити елемент у цьому просторі імен:

xml.CreateElement("loner", "whatever:name-space-1.0")

Якщо ви хочете, щоб <loner>елемент не знаходився в просторі імен, то створений XML - це саме те, що вам потрібно, і вам не слід турбуватися про xmlnsатрибут, який автоматично додається для вас.


3
Проблема полягає в невідповідних XML-аналізаторах (як правило, від Microsoft), які не справляються з xmnls = "").
Крейг Трейдер,

2
/. називається. Вони хочуть, щоб їх випадкові MS-коментарі не відступали.

@W. Крейг Трейдер - не можу сказати, що я зіткнувся з цим як з проблемою. Приклад?
Кев

1
Правильно, я не хочу, щоб у вузла <loner /> був простір імен, але я також не хочу, щоб він мав порожній атрибут простору імен (xmlns). Мої міркування - це просто побачити, чи можу я відповідати виводу XML певного протоколу, який налаштований так.
Ніл К. Обремський,

5
Це не було випадковим ударом. Блок додатків Microsoft Updater використовує XML-маніфест, щоб визначити, що доставити клієнту. На жаль, аналізатор Manifest не може впоратися з xmlns = ""; Мені довелося написати постпроцесор, який би викреслював порожні атрибути xmlns.
Крейг Трейдер,

7

Оскільки корінь знаходиться у нефіксованому просторі імен, будь-яке дочірнє коріння, яке хоче бути без простору імен, повинно виводитись як ваш приклад. Рішенням було б приєднання кореневого елемента так:

<w:root xmlns:w="whatever:name-space-1.0">
   <loner/>
</w:root>

код:

XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement( "w", "root", "whatever:name-space-1.0" );
doc.AppendChild( root );
root.AppendChild( doc.CreateElement( "loner" ) );
Console.WriteLine(doc.OuterXml);

Дякую, але додавання простору імен до фактичного кореня порушить мій XML стосовно конкретного протоколу, з яким я працюю.
Ніл К. Обремський,

Ах! Я зрозумів більше, що ти казав, і врахував це, написавши власну відповідь. Спасибі Джеремі
Ніл К. Обремський

0

Якщо можливо, створіть клас серіалізації, тоді виконайте:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(yourType);
serializer.Serialize(xmlTextWriter, someObject, ns);

Це безпечніше, і ви можете керувати просторами імен за допомогою атрибутів, якщо вам дійсно потрібен додатковий контроль.


0

Я вирішив проблему, використовуючи заводський зразок. Я створив завод для об'єктів XElement. Як параметр для створення фабрики я вказав об'єкт XNamespace. Отже, щоразу, коли завод створює XElement, простір імен додається автоматично. Ось код заводу:

internal class XElementFactory
{
    private readonly XNamespace currentNs;

    public XElementFactory(XNamespace ns)
    {
        this.currentNs = ns;
    }

    internal XElement CreateXElement(String name, params object[] content)
    {
        return new XElement(currentNs + name, content);
    }
}

1
ОП запитували про XmlDocument, ні XDocument.
Джон Сондерс

0

Так, ви можете запобігти XMLNS з XmlElement. Перше створення часу, він настає: так

<trkpt lat="30.53597" lon="-97.753324" xmlns="">
    <ele>249.118774</ele>
    <time>2006-05-05T14:34:44Z</time>
</trkpt>

Змініть код: і передайте xml простір імен так

C # код:

XmlElement bookElement = xdoc.CreateElement("trkpt", "http://www.topografix.com/GPX/1/1");
bookElement.SetAttribute("lat", "30.53597");
bookElement.SetAttribute("lon", "97.753324");
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.