Префиксы пространства имен с IXmlSerializable - PullRequest
7 голосов
/ 28 сентября 2011

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

Определение класса, например.

using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
[XmlRoot("Classy", Namespace = XML_NS)]
public class TestClass : IXmlSerializable
{
    private const string XML_PREFIX = ""; // default namespace
    private const string XML_NS = "www.123.com";
    private const string XML_MEMBER_PREFIX = "me";
    private const string XML_MEMBER_NS = "member.com";

    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces xmlsn {
        get {
            XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
            xsn.Add(XML_PREFIX, XML_NS);
            xsn.Add(XML_MEMBER_PREFIX, XML_MEMBER_NS);
            return xsn;
        }
    }

    void IXmlSerializable.WriteXml(XmlWriter writer) {
        writer.WriteElementString(XML_MEMBER_PREFIX, "Member1.5",
                                  XML_MEMBER_NS, Member1);
        writer.WriteElementString(XML_MEMBER_PREFIX, "Member2.5",
                                  XML_MEMBER_NS, Member2.ToString());
        writer.WriteElementString(XML_PREFIX, "Member3.5", XML_NS, Member3);
    }

    //[XmlElement(ElementName = "Member1.5", Namespace = XML_MEMBER_NS)]
    public string Member1 {
        get { return "init"; }
        set { ; }
    }
    //[XmlElement(ElementName = "Member2.5", Namespace = XML_MEMBER_NS)]
    public int Member2 {
        get { return 3; }
        set { ; }
    }
    //[XmlElement(ElementName = "Member3.5", Namespace = XML_NS)]
    public string Member3 {
        get { return "default namespace"; }
        set { ; }
    }

    // ignore ReadXml/GetSchema
    XmlSchema IXmlSerializable.GetSchema() { return null; }
    void IXmlSerializable.ReadXml(XmlReader reader) { return; }
}

При сериализации через:

TestClass tc = new TestClass();
XmlSerializer ser = new XmlSerializer(typeof(TestClass)); 
ser(writer, tc, tc.xmlsn); // just a plain XmlWriter to Console.Out

вывод

<?xml version="1.0" encoding="utf-8"?>
<Classy xmlns="www.123.com">
    <me:Member1.5 xmlns:me="member.com">init</me:Member1.5>
    <me:Member2.5 xmlns:me="member.com">3</me:Member2.5>
    <Member3.5>default namespace</Member3.5>
</Classy>

Результат, который я ожидал, был:

<?xml version="1.0" encoding="utf-8"?>
<Classy xmlns:me="member.com" xmlns="www.123.com">
    <me:Member1.5>init</me:Member1.5>
    <me:Member2.5>3</me:Member2.5>
    <Member3.5>default namespace</Member3.5>
</Classy>

Второй вывод XmlSerializer, если реализация класса IXmlSerializable удалена и вы раскомментировали декораторы XmlElement. Я знаю, что оба возвращенных XML-документа действительны, но было бы неплохо попытаться удалить избыточные объявления пространства имен. Я бы предположил, что такая возможность возможна, поскольку IXmlSerializable призван обеспечить больший контроль над сериализацией / десериализацией вашего класса.

Обновление: Очень интересный ответ предложил изменить XmlWriterSettings! Похоже, это все прояснит, изменив свойство NamespaceHandling. Однако это все еще приводит к тому, что пространства имен переписываются для каждого члена. Полный код сериализации ниже:

XmlSerializer ser = new XmlSerializer(typeof(TestClass));
TestClass tc = new TestClass();

XmlWriterSettings xmlSet = new XmlWriterSettings();
xmlSet.Encoding = System.Text.Encoding.UTF8;
xmlSet.Indent = true;
xmlSet.NamespaceHandling = NamespaceHandling.OmitDuplicates;
XmlWriter writer = XmlWriter.Create(Console.Out, xmlSet);

ser.Serialize(writer, tc); // with/without tc.xmlsn same result
writer.Flush();
writer.Close();

Ответы [ 3 ]

1 голос
/ 15 апреля 2012

Я просто добавил строковый атрибут в WriteXml.Это сработало!

void IXmlSerializable.WriteXml(XmlWriter writer) {
        writer.WriteAttributeString("xmlns:me", "member.com");
        writer.WriteAttributeString("xmlns", "www.123.com");
        writer.WriteElementString(XML_MEMBER_PREFIX, "Member1.5",
                                  XML_MEMBER_NS, Member1);
        writer.WriteElementString(XML_MEMBER_PREFIX, "Member2.5",
                                  XML_MEMBER_NS, Member2.ToString());
        writer.WriteElementString(XML_PREFIX, "Member3.5", XML_NS, Member3);
    }

и удалило [XmlRoot("Classy", Namespace = XML_NS)] и свойство xmlsn из класса.

0 голосов
/ 28 апреля 2014

Использование WriteAttributeString как предложено не совсем правильно.Вот пример того, как правильно его использовать:

В методе WriteXml в начале добавьте что-то вроде этого:

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
        writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
0 голосов
/ 05 октября 2011

Вам нужно установить XmlWriterSetting для его работы. смотри ниже пожалуйста

http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.aspx

...