2013-11-27 2 views
0

У меня возникает следующая проблема. Всякий раз, когда я использую стандартную сериализацию XML в моем классе C#, пространства имен xsi и xsd автоматически добавляются механизмом сериализации .NET. Однако, когда сериализация определена через IXmlSerializable, пространства имен не добавляются.Пространства имен xsi и xsd отсутствуют при использовании пользовательского IXmlSerializable

Пример: этот код:

class Program 
{ 
    static void Main(string[] args) 
    { 
     OutputSerialized(new Outer() { Inner = new Inner() }); 
     OutputSerialized(new OuterCustom() { Inner = new Inner() }); 
    } 

    static void OutputSerialized<T>(T t) 
    { 
     var sb = new StringBuilder(); 
     using (var textwriter = new StringWriter(sb)) 
      new XmlSerializer(typeof(T)).Serialize(textwriter, t); 
     Console.WriteLine(sb.ToString()); 
    } 
} 

[Serializable] public class Inner { } 

[Serializable] public class Outer { public Inner Inner { get; set; } } 

public class OuterCustom : IXmlSerializable 
{ 
    public Inner Inner; 

    public void WriteXml(System.Xml.XmlWriter writer) 
    { 
     writer.WriteStartElement("Inner"); 
     new XmlSerializer(typeof(Inner)).Serialize(writer, Inner); 
     writer.WriteEndElement(); 
    } 

    public System.Xml.Schema.XmlSchema GetSchema() { return null; } 
    public void ReadXml(System.Xml.XmlReader reader) { /**/ } 
} 

производит следующий вывод:

<?xml version="1.0" encoding="utf-16"?> 
<Outer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Inner /> 
</Outer> 
<?xml version="1.0" encoding="utf-16"?> 
<OuterCustom> 
    <Inner> 
    <Inner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> 
    </Inner> 
</OuterCustom> 

Вы можете увидеть, что сериализованная образуют OuterCustom «s отсутствует в xsd и xsi пространств имен.

Как я могу сделать мой OuterCustom вести себя так же, как Outer? Я что-то пропустил в своем коде? Я неправильно делаю сериализацию?

Есть много вопросов здесь, на SO о , как избавиться от дополнительных пространств имен, но мне кажется, что никто не спросил о , как получить их обратно.

+0

Нет никакой разницы между двумя XML-образцами с точки зрения XML ... Вы пытаетесь выполнить поиск по строкам/регулярным выражениям в XML? –

+0

@Alexei Levenkov: Ну, я пытаюсь украсить XML-вывод: в самом коде у меня много классов Inner, каждый из которых содержит дополнительные пространства имен (что выглядит довольно уродливо). В любом случае мне интересно, почему XML-сериализатор делает разные вещи в двух случаях, они кажутся «идентичными». – Vlad

+0

Попробовали вручную написать атрибуты xmlns в 'OuterCustom' с помощью [WriteAttributeString] (http://msdn.microsoft.com/en-us/library/73z46xs1%28v=vs.110%29.aspx)? –

ответ

1

Прежде всего - нет разницы между упомянутыми версиями XML для совместимого синтаксического анализа XML. На самом деле не имеет значения, если/how/где префиксы пространства имен определены до тех пор, пока узлы имеют правильные пространства имен.

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

Можно записывать атрибуты xmlns везде, где это необходимо, поскольку они не конфликтуют на одном узле. Используйте XmlWriter.WriteAttributeString метод, чтобы добавить их:

writer.WriteAttributeString(
    "xmlns", "prefix", null, "urn:mynamespace"); 

Во избежание дублирования деклараций - проверить, если префикс уже определен для данного пространства имен с помощью XmlWriter.LookupPrefix

Пример кода для обеспечения xsd и xsi префиксы (Влад):

const string xsiNamespace = System.Xml.Schema.XmlSchema.InstanceNamespace; 
const string xsdNamespace = System.Xml.Schema.XmlSchema.Namespace; 

public static void EnsureDefaultNamespaces(System.Xml.XmlWriter writer) 
{ 
    if (writer.LookupPrefix(xsiNamespace) == null) 
     writer.WriteAttributeString("xmlns", "xsi", null, xsiNamespace); 
    if (writer.LookupPrefix(xsdNamespace) == null) 
     writer.WriteAttributeString("xmlns", "xsd", null, xsdNamespace); 
} 

Альтернативный подход, если дополнительные изменения, необходимые для достижения красивого XML, должны позволить завершить сериализацию и обработать XML для настройки префиксов (т.е. желаемые префиксы, собирать все пространства имен и определять все сверху). Можно либо прочитать XML с кодом C#, либо даже преобразовать XSLT.