Правильное управление пространством имен в .NET XmlWriter

Я широко использую технологии .NET XML в своей работе. Одна из вещей, которые мне очень нравятся, это движок XSLT, точнее его расширяемость. Однако есть один маленький кусочек, который продолжает вызывать раздражение. Ничего особенного или чего-то, с чем мы не можем жить, но это мешает нам создавать прекрасный XML, который мы хотели бы создать.

Одна из вещей, которые мы делаем, - это преобразуем встроенные узлы и импортируем узлы из одного документа XML в другой.

К сожалению, когда вы сохраняете узлы в XmlTextWriter (фактически независимо от того, что возвращает XmlWriter.Create(Stream)), определения пространства имен XmlTextWriter туда независимо от того, необходимо это (ранее определено) или нет. Вы получаете вид следующего XML:

<root xmlns:abx="http://bladibla">  
     <abx:child id="A">  
         <grandchild id="B">
             <abx:grandgrandchild xmlns:abx="http://bladibla" />  
         </grandchild>  
     </abx:child>  
</root>

У кого-нибудь есть предложение относительно того, как убедить .NET быть эффективным в отношении его определений пространства имен?

PS. В качестве дополнительного бонуса я хотел бы переопределить пространство имен по умолчанию, меняя его, когда я пишу узел.

Ответы

Ответ 1

Используйте этот код:

using (var writer = XmlWriter.Create("file.xml"))
{
    const string Ns = "http://bladibla";
    const string Prefix = "abx";

    writer.WriteStartDocument();

    writer.WriteStartElement("root");

    // set root namespace
    writer.WriteAttributeString("xmlns", Prefix, null, Ns);

    writer.WriteStartElement(Prefix, "child", Ns);
    writer.WriteAttributeString("id", "A");

    writer.WriteStartElement("grandchild");
    writer.WriteAttributeString("id", "B");

    writer.WriteElementString(Prefix, "grandgrandchild", Ns, null);

    // grandchild
    writer.WriteEndElement();
    // child
    writer.WriteEndElement();
    // root
    writer.WriteEndElement();

    writer.WriteEndDocument();
}

Этот код создавал желаемый результат:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:abx="http://bladibla">
  <abx:child id="A">
    <grandchild id="B">
      <abx:grandgrandchild />
    </grandchild>
  </abx:child>
</root>

Ответ 2

Я не уверен, что это то, что вы ищете, но вы можете использовать этот код при начале записи в поток Xml:

myWriter.WriteAttributeString("xmlns", "abx", null, "http://bladibla");

XmlWriter должен помнить об этом, а не переписывать его больше. Он не может быть пуленепробиваемым на 100%, но он работает большую часть времени.

Ответ 3

Вы пробовали это?

Dim settings = New XmlWriterSettings With {.Indent = True,
                                          .NamespaceHandling = NamespaceHandling.OmitDuplicates,
                                          .OmitXmlDeclaration = True}
Dim s As New MemoryStream
Using writer = XmlWriter.Create(s, settings)
    ...
End Using

Интересно, что "NamespaceHandling.OmitDuplicates"