Изменить автоматически сгенерированный класс 'обработка пространства имен XmlSerialization - PullRequest
0 голосов
/ 27 июня 2018

Я сейчас нахожусь в процессе создания группы файлов, которые затем будут использоваться другой программой. Большинство из них являются XML-файлами. Естественно, я извлек файлы .xsd из программы и использовал инструмент xsd.exe для автоматической генерации C # -классов, который работает довольно хорошо.

Проблема

Сериализация автоматически сгенерированного класса приводит к xml-файлу, подобному этому:

<root xmlns="ns1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <group xmlns="">
        <item>foo</item>
        <item>bar</item>
    </group>
</root>

И xsi, и xsd не используются во всем, что я нашел до сих пор, но это не должно быть проблемой.

XML-код, ожидаемый программой, будет выглядеть примерно так:

<n1:root xmlns:n1="ns1">
    <group>
        <item>foo</item>
        <item>bar</item>
    </group>
</n1:root

При десериализации оба xml должны приводить к одному и тому же результату, поэтому я не помещаю ошибку в xsd.exe.

Однако при попытке открыть сгенерированный XML-файл в программе выдается ошибка «Ссылка на объект не установлена ​​на экземпляр объекта». И xmlns:xsi, и xmlns:xsd должны быть удалены, и он должен использовать xmlns:n1 вместо пространства имен по умолчанию.

Что я пробовал

Сначала я подумал, что мог бы просто сериализовать класс вручную, используя IXmlSerializable, однако это приводит к ошибке времени выполнения при сериализации, поскольку xsd.exe автоматически добавляет XmlTypeAttribute и XmlRootAttribute.

Произведенная ошибка читает InvalidOperationException: Only XmlRoot attribute may be specified for the type myNs.MyClass. Please use XmlSchemaProviderAttribute to specify schema type.

Я не думаю, что использование XmlSchemaProviderAttribute является хорошей идеей, потому что это отвергает идею автоматического создания класса из заданной схемы. (Схема, вероятно, изменится в будущих версиях программы)


Если вам нужен минимальный пример, вот код, который выполняется на rextester.com : (обратите внимание, что rextester использует .NET Framework 4.5, а я использую .NET Framework 4.7, поэтому любые ответы, использующие новые функции приветствуются)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Rextester
{
    // AUTOGENERATED
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.2558.0")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.somens.com")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.somens.com", IsNullable=false)]
    public partial class Test {
        [System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [System.Xml.Serialization.XmlArrayItemAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
        public Item[] Group { get; set; }
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.2558.0")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.somens.com")]
    public partial class Item {
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public int Value { get; set; }
    }

    // CUSTOM
    public partial class Test : IXmlSerializable
    {
        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(XmlWriter writer)
        {
            foreach (var item in Group) {
                writer.WriteStartElement("item");
                writer.WriteAttributeString("Value", item.Value.ToString());
                writer.WriteEndElement();
            }
        }

    }


    public class Program
    {
        public static void Main(string[] args)
        {
            var t = new Test();
            t.Group = new Item[] { new Item { Value = 5}, new Item { Value = 10} };

            var serializer = new XmlSerializer(typeof(Test));
            serializer.Serialize(Console.Out, t);
        }
    }
}

1 Ответ

0 голосов
/ 27 июня 2018

Я могу полностью упустить момент, потому что я не знаю, что вы имеете в виду под "извлечением файлов .xsd из программы", и при этом я не знаю, какую интеграцию вы пишете.

Если вашей конечной целью является просто получить правильное пространство имен, чтобы программа использовала ваши данные, отбросьте все автоматически сгенерированные атрибуты XmlSerialier и скажите классу и сериализатору, как вы хотите, чтобы все выглядело. Иногда меньше - больше, когда дело доходит до сериализатора, и он сам сделает большую работу, если вы позволите.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Rextester
{

    [XmlRoot("root", Namespace = "ns1")]
    public partial class Test 
    {
        [XmlArray(ElementName = "Group", Namespace = "")]
        public Item[] Group { get; set; }
    }

    public partial class Item
    {
        public int Value { get; set; }
    }

     public class Program
    {
        public static void Main(string[] args)
        {
            var t = new Test();
            t.Group = new Item[] { new Item { Value = 5 }, new Item { Value = 10 } };
            XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
            xsn.Add("n1", "ns1");
            var serializer = new XmlSerializer(typeof(Test));
            serializer.Serialize(Console.Out, t,xsn);
        }
    }
}

Какие выходы.

<?xml version="1.0" encoding="IBM437"?>
<n1:root xmlns:n1="ns1">
  <Group>
    <Item>
      <Value>5</Value>
    </Item>
    <Item>
      <Value>10</Value>
    </Item>
  </Group>
</n1:root>

Это не совсем похоже на ваш пример, но с некоторыми манипуляциями с вашим классом вы можете комбинировать теги Item и Value.

...