C# System.Xml.Serialization — используйте только и никогда

#c# #xml #xml-serialization #xmlserializer #xmltextwriter

#c# #xml #xml-сериализация #xmlserializer #xmltextwriter

Вопрос:

У меня странная проблема с моим клиентом — я читаю XML-документ (фактически документ InfoPath) с помощью XmlSerializer , изменяю его, затем выписываю XML-документ с помощью XmlSerializer , а затем добавляю некоторые инструкции по обработке с помощью XmlTextWriter . Все работает хорошо, и результирующий документ фактически полностью соответствует XML и может быть прочитан InfoPath. Однако одно изменение, которое происходит в структуре, заключается в том, что в исходном документе все пустые теги записаны в форме <A></A> , и когда мой документ написан, он становится <A/> . Фактически точно так же из-за стандартов XML. Но у моего клиента (крупной компании), по-видимому, есть несколько жестко запрограммированных сценариев проверки <A></A> , и они терпят неудачу. Теперь он расстроен, ему лень менять свои скрипты, и он хочет <A></A> обозначения! Как я могу настроить XmlTextWriter для этого?

Комментарии:

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

2. Я думал, что библиотека Net соответствует спецификации XML. Я думаю, что InfoPath не соответствует.

3. Оба . NET и Infopath соответствуют — собственные сценарии проверки моего клиента нет.

Ответ №1:

Вы можете сделать это, предоставив XmlSerializer свой собственный XmlWriter потомок, который переопределил бы WriteEndElement метод. По умолчанию этот метод создает пустой элемент ( <a /> ) или закрывающий элемент ( </a> ) в зависимости от содержимого выводимого элемента. Вы можете изменить поведение, чтобы всегда создавать полностью закрывающий элемент.

 public class MyXmlWriter : XmlTextWriter
{
    // …constructors etc. omitted for the sake of simplicity…

    public override void WriteEndElement()
    {
        // this should do the trick
        WriteFullEndElement();
    }
}
  

Однако требуется еще некоторая работа, например, над Async версией этого метода, но в принципе, ее должно быть легко достичь, как описано выше. Я бы рекомендовал изучить исходный код XmlTextWriter.WriteEndElement и получить версию, которая лучше подходит для вашего случая.

Комментарии:

1. XmlTextWriter не переопределяет WriteEndElementAsync (а реализация XmlWriter просто выдает исключение), поэтому я думаю , что этого кода может быть достаточно самого по себе?

2. Просто перенял решение — работает так, как хотелось! Однако один вопрос — теперь он удаляется при новом переносе строки. Есть какой-нибудь способ это контролировать?

3. @PetrOsipov Посмотрите на XmlWriterSettings , которые предоставляют множество настроек, которые могут быть полезны при дальнейшем форматировании выходных данных.

4. На самом деле, нет настроек, которые могли бы этим управлять. По крайней мере, ни один из них не дает желаемого эффекта. Сейчас я пытаюсь переопределить WriteFullEndElement. Хотя это переопределяемо, я не могу просто взять официальную библиотеку классов и исправить то, что я хочу — используется множество внутренних, частных или защищенных полей и т.д., Что затрудняет исправление функциональности….

Ответ №2:

Честно говоря, я думаю, что если вы собираетесь использовать встроенный сериализатор, то вам было бы лучше выполнить поиск / замену. Не похоже, что вы можете переопределить фактическую форму тегов, по крайней мере, я не видел способа сделать это, даже переопределяя некоторые методы.

В результате я бы поставил галочку, которая говорит, что если тег пуст, введите значение, такое как "[[[EMPTYVALUE]]]" , чтобы в итоге получилось

<A>[[[EMPTYVALUE]]]</A>

Затем сгенерируйте ваш XML-файл и перед сохранением XML-файла преобразуйте его в строку и замените "<A>[[[EMPTYVALUE]]]</A>" на "<A></A>"

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