Как получить плоский список возможных элементов XML по порядку из объекта XmlSchemaObject в.NET
У меня есть XML-схема из XmlSchemaSetProvider и мне нужен список всех возможных XML-элементов (имен), которые могут быть в указанном типе в правильном порядке.
Схема использует расширения XML-схемы, сложные типы, последовательности...
Есть ли хороший способ сделать это?
Причина: у меня есть собственный сериализатор XML, который зависел от порядка свойств, возвращаемого при отражении типа.NET, но это (задокументировано как неопределенное) поведение порядка изменилось в MSBuild 14. Теперь мне нужно исправить порядок, не помещая около 1000 XmlElement.Order на всех свойства класса. Таким образом, идея состоит в том, чтобы обнаружить / исправить порядок из информации XSD и использовать ее для исправления XML.
2 ответа
В общем случае то, что вы просите, невозможно. Если тип может содержать N разных элементов, то можно разработать схему, в которой некоторые подмножества элементов могут появляться в различной последовательности в зависимости от контекста. Таким образом, не существует единой определенной последовательности для всех элементов схемы. Конкретные схемы, которые вы имеете в виду, могут не страдать от этой проблемы (хотя вы должны предполагать наихудшее, пока не докажете, что это не так). Если вы считаете, что для этого ограниченного набора схем возможно решение, вам нужно будет разработать собственное решение, и я бы посоветовал вам разработать его довольно консервативно. В частности, вы должны включить утверждения, которые проверяют наличие сценариев, нарушающих ваше правило "только одна возможная последовательность".
Сказав все это, мне было бы интересно понять бизнес-требования, стоящие за вашей просьбой. Возможно, это можно решить другими (более легкими) способами.
В конце я выбрал другой подход, основанный на макете класса вместо схемы XML. Я добавил "[PropertyLineNumber]" во все свойства с помощью одного поиска и замены и использовал его для отражения, чтобы получить надежный заказ. Порядок идет по цепочке наследования, затем по номеру строки. Здесь атрибут (использующий C# 6), который я использовал, чтобы сделать информацию о номере строки доступной через отражение для нашего сериализатора.
[AttributeUsage(AttributeTargets.Property)]
public sealed class PropertyLineNumberAttribute : Attribute
{
public int LineNumber { get; }
public PropertyLineNumberAttribute([CallerLineNumber] int lineNumber = 0)
{
LineNumber = lineNumber;
}
}