Сложный синтаксический анализ XML в C#
Мне нужно проанализировать сложный и большой (более 100 МБ) XML-файл. К счастью, у меня есть определения схемы XML, но, к сожалению, я не могу использовать xsd2code для генерации автоматической десериализации XML, поскольку на верхнем уровне XML используются абстрактные типы сообщений. Структура файла XML выглядит следующим образом:
<Head>
<Batch>
<Dog></Dog>
<Dog></Dog>
</Batch>
</Head>
XSD определяет партию для содержания абстрактных животных, а не собак. Xsd2Code может создавать класс Dog с правильными атрибутами XML, но класс dog находится внутри другого файла xsd. Я пытался вставить все xsd вместе, но это не помогло исправить это.
Есть ли хороший способ, как Linq to XML или Xpath, перебирать элементы в Batch и создавать экземпляры Dog без необходимости синтаксического анализа Dog вручную?
1 ответ
Есть ли хороший способ, как Linq to XML или Xpath, перебирать элементы в Batch и создавать экземпляры Dog без необходимости синтаксического анализа Dog вручную?
Это зависит от того, что вы подразумеваете под "вручную". Я обнаружил, что полезно иметь шаблон, в котором каждый соответствующий класс имеет статический FromXElement
фабричный метод (или конструктор, принимающий XElement
) который извлекает соответствующие детали. С LINQ to XML это довольно просто, например,
public static Dog FromXElement(XElement element)
{
// Or whatever...
return new Dog((string) element.Element("Name"),
(double) element.Element("Weight"));
}
Тогда вы можете использовать:
List<Dog> dogs = batch.Elements("Dog")
.Select(x => Dog.FromXElement(x))
.ToList();
(Вы можете использовать Select(Dog.FromXElement)
вместо этого - это зависит от того, какую версию C# вы используете.)
Для обработки всех животных в партии, вы, вероятно, захотите что-то вроде:
private static readonly Dictionary<string, Func<XElement, Animal>> Factories =
new Dictionary<string, Func<XElement, Animal>>
{
{ "Dog", Dog.FromXElement },
{ "Cat", Cat.FromXElement },
// etc
}
...
List<Animal> animals = batch.Elements()
.Select(x => Factories[x.Name.LocalName](x))
.ToList();