Сериализация элемента XML и элемента массива XML с одинаковым именем - PullRequest
0 голосов
/ 30 октября 2018

Я хочу сериализовать XML-документы из сторонних сервисов, которые могут входить в любом из двух форматов (я добавил отступ для облегчения чтения):

1

<STADMessage>Invalid Request, no content provided!</STADMessage>

2

<STADMessage>
    <Message>Invalid Request, see log for detail using reference: ASDFL210359872305982035</Message>
</STADMessage>

Прямо сейчас я взламываю XML-документ до его сериализации с помощью следующего кода

xmlDocument.Replace("<STADMessage><Message>", "<STADMessages><Message>")
           .Replace("</Message></STADMessage>", "</Message></STADMessages>");

Фрагмент сериализованного класса

[XmlElement(ElementName = "STADMessage", IsNullable = true)]
public string STADMessage { get; set; }

[XmlArray(ElementName = "STADMessages", IsNullable = true)]
[XmlArrayItem("Message", typeof(string))]
public List<string> STADMessages { get; set; }

Есть ли более чистый путь?

1 Ответ

0 голосов
/ 30 октября 2018

Если вы можете заставить их изменить его на правильную структуру, как рекомендует @FrankerZ, это было бы идеально. Если вы не можете, надеюсь, это поможет.

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

Измените тип вашего свойства STADMessage на пользовательский тип (я назову его STADMessage, черт возьми):

[XmlElement(ElementName = "STADMessage", IsNullable = true)]
public STADMessage STADMessage { get; set; }

А вот STADMessage класс:

public class MySTADMessage : IXmlSerializable
{
    public string Message { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        // IsNullable = true is ignored, apparently.  You won't get an actual
        // null for properties deserialized this way because the serializer
        // already created an instance of this class.
        if (reader.GetAttribute("nil", XmlSchema.InstanceNamespace) == "true")
            return;

        reader.ReadStartElement();

        while (reader.NodeType == XmlNodeType.Whitespace)
            reader.Read();

        if (reader.NodeType == XmlNodeType.Text)
        {
            Message = reader.ReadContentAsString();
        }
        else if (reader.NodeType == XmlNodeType.Element)
        {
            if (reader.Name != "Message")
                throw new Exception("Unexpected element name.");

            reader.ReadStartElement();
            if (reader.NodeType == XmlNodeType.Text)
            {
                Message = reader.ReadContentAsString();
            }
            else
            {
                throw new Exception("Unexpected node type.");
            }
            reader.ReadEndElement();
        }
        else
        {
            throw new Exception("Unexpected node type.");
        }
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        // Not having the extra Message element is simpler.
        writer.WriteString(Message);
    }
}

Это грубо, он не вполне реализует IXmlSerializable правильно по сегодняшним стандартам, и, вероятно, не все учитывает, но он должен помочь вам начать.

...