Мне нужно проанализировать XML-файл со следующей структурой: ИЗМЕНИТЬ
…
<?xml version = "1.0" encoding = "windows-1252" ?>
<TABLE>
<COMPO>
<alim_code> 1000 </alim_code>
<const_code> 56700 </const_code>
<teneur> 0 </teneur>
<min missing = " " />
<max missing = " " />
<code_confiance> D </code_confiance>
<source_code missing = "." />
</COMPO>
<COMPO>
<alim_code> 1000 </alim_code>
<const_code> 60000 </const_code>
<teneur> 37,5 </teneur>
<min> 37,3 </min>
<max> 37,6 </max>
<code_confiance> D </code_confiance>
<source_code> 38 </source_code>
</COMPO>
</TABLE>
…
Как видите, некоторые поля описываются по-разному, когда значение известно или отсутствует. Я пытался использовать ReadXml () в DataSet, но, похоже, он не работает с «структурой переменных». Похоже, решение состоит в том, чтобы использовать Xdocument и LINQ, но я ничего не знаю о LINQ, и мне не удалось написать рабочий код.
Я был бы признателен, если бы кто-нибудь мог показать мне возможный код для анализа и печати (или, еще лучше, добавления в базу данных) содержимого этого типа XML-файла.





Linq здесь не поможет. Что вы можете сделать, так это создать DTO для вашего xml, используя образец xml, который содержит все атрибуты и узлы, которые могут быть возвращены в xml.
а затем десериализуйте xml в этот тип.
Ваши классы будут чем-то вроде следующего из создаваемого выше xml:
[XmlRoot(ElementName = "min")]
public class Min {
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
}
[XmlRoot(ElementName = "max")]
public class Max {
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
}
[XmlRoot(ElementName = "source_code")]
public class Source_code {
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
}
[XmlRoot(ElementName = "COMPO")]
public class COMPO {
[XmlElement(ElementName = "alim_code")]
public string Alim_code { get; set; }
[XmlElement(ElementName = "const_code")]
public string Const_code { get; set; }
[XmlElement(ElementName = "teneur")]
public string Teneur { get; set; }
[XmlElement(ElementName = "min")]
public Min Min { get; set; }
[XmlElement(ElementName = "max")]
public Max Max { get; set; }
[XmlElement(ElementName = "code_confiance")]
public string Code_confiance { get; set; }
[XmlElement(ElementName = "source_code")]
public Source_code Source_code { get; set; }
}
Теперь вы можете использовать класс XmlSerializer для его десериализации:
XmlSerializer serializer = new XmlSerializer(typeof(List<COMPO>));
List<COMPO> compos = null;
using (var reader = new StringReader(xml))
{
compos = (List<COMPO>)serializer.Deserialize(reader);
}
В этом случае добавьте другой тип для Table, который будет:
[XmlRoot(ElementName = "Table")]
public class Table {
[XmlElement(ElementName = "COMPO")]
public List<COMPO> COMPO { get; set; }
}
и теперь соответствующим образом отрегулируйте код десериализации:
XmlSerializer serializer = new XmlSerializer(typeof(Table));
Table table = null;
using (var reader = new StringReader(xml))
{
compos = (Table)serializer.Deserialize(reader);
}
вы можете использовать xmltocsharp.azurewebsites.net для создания классов C# для вашего xml
Я добавил класс Table (созданный с использованием предоставленной вами ссылки) и изменил средство чтения, но все еще получаю ошибку исключения в документе XML (1,1). Неверные данные на уровне корня, строка 1, позиция 1 (это приблизительный перевод!). Файл идет с data.gouv.fr/fr/datasets/… compo_2017 11 21.xml
убедитесь, что xml действителен, ошибка, похоже, связана с форматом xml
Похоже, что предоставленный вами код может обрабатывать структуру XML, когда присутствует «отсутствующее» поле, но нет другой формы. поэтому <min missing = "" /> работает, но не <min> 37,3 </min>. Поэтому это решение не работает для моей проблемы.
этого не должно быть, он отобразит только те свойства, которые доступны
Извините, это моя ошибка. Я вызывал StringReader () с xmlFileName. После передачи ему содержимого, возвращенного File.ReadAllText (), он теперь работает отлично. Спасибо
@DrCoolZic не забудьте отметить ответ, если он вам помог :)
На самом деле я все еще не могу получить минимальные и максимальные значения. Когда используется атрибут "missing", класс Min содержит отсутствующее поле с content = "", а если отсутствует, то отсутствующее поле имеет значение NULL. Хорошо. Однако нет способа получить минимальное значение (например, 37,3 во второй записи предоставленного примера). Я не уверен, что [XmlElement (ElementName = "min")] public Min Min {get; набор; } действительно что-то значит. В отладчике Min содержит только отсутствующее поле, которое может быть нулевым или содержать строку, но нет места для хранения минимального значения ???
@DrCoolZic, можете ли вы создать демонстрационную скрипку, демонстрирующую проблему?
Я не понимаю вашу просьбу "демо рабочий пример"? Вы хотите, чтобы я опубликовал код, который использую? В качестве тестового примера я использую очень простой XML-файл, показанный в вопросе. Опять же, проблема с вашим решением заключается в том, что нет места для хранения минимальных / максимальных значений, если они указаны? Или я что-то упускаю? У классов Min и Max есть только одно поле «отсутствует», но нет места для хранения значения.
Я бы использовал Xml Linq. Есть некоторые элементы, которые могут иметь значение NULL, с которыми вам нужно работать правильно. См. Код ниже
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
IFormatProvider provider = CultureInfo.InvariantCulture;
List<Compo> compos = doc.Descendants("COMPO").Select(x => new Compo() {
alim_code = (int?)x.Element("alim_code"),
const_code = (int?)x.Element("const_code"),
teneur = (string)x.Element("teneur") == "" ? null : (decimal?)Convert.ToDecimal((string) x.Element("teneur"),provider),
min = (string)x.Element("min") == "" ? null : (decimal?)Convert.ToDecimal((string) x.Element("teneur"),provider),
max = (string)x.Element("max") == "" ? null : (decimal?)Convert.ToDecimal((string) x.Element("teneur"),provider),
code_confiance = (string)x.Element("code_confiance"),
source_code = (string)x.Element("source_code") == "" ? null : (int?)int.Parse(((string)x.Element("source_code")).Trim())
}).ToList();
}
}
public class Compo
{
public int? alim_code {get; set;}
public int? const_code {get; set;}
public decimal? teneur {get; set;}
public decimal? min {get; set;}
public decimal? max {get; set;}
public string code_confiance {get; set;}
public int? source_code { get; set; }
}
}
Мне сложно понять этот код Linq. Не могли бы вы изменить, чтобы добавить корневой элемент ТАБЛИЦА, который я добавил в описание. Спасибо
Зачем вам стол. класс? Все, что вам нужно, это List <Compo>. Метод linq Descendants () не требует полного пути, только имя элемента.
попробовал ваш код, но я получаю исключение с сообщением: неверный формат входной строки, но я понятия не имею, что это значит.
Я внес изменения в обработку пустых элементов.
Хорошо, я понял. Я опробую более подходящие типы и дам вам знать. Спасибо
Рабочее решение на основе предложения Эхсан-Саджад :)
[XmlRoot(ElementName = "min")]
public class Min
{
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot(ElementName = "max")]
public class Max
{
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot(ElementName = "source_code")]
public class Source_code
{
[XmlAttribute(AttributeName = "missing")]
public string Missing { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot(ElementName = "COMPO")]
public class COMPO
{
[XmlElement(ElementName = "alim_code")]
public string Alim_code { get; set; }
[XmlElement(ElementName = "const_code")]
public string Const_code { get; set; }
[XmlElement(ElementName = "teneur")]
public string Teneur { get; set; }
[XmlElement(ElementName = "min")]
public Min Min { get; set; }
[XmlElement(ElementName = "max")]
public Max Max { get; set; }
[XmlElement(ElementName = "code_confiance")]
public string Code_confiance { get; set; }
[XmlElement(ElementName = "source_code")]
public Source_code Source_code { get; set; }
}
[XmlRoot(ElementName = "TABLE")]
public class TABLE
{
[XmlElement(ElementName = "COMPO")]
public List<COMPO> COMPO { get; set; }
}
private void ReadCompoWithSerializer()
{
string xmlFile = "test.xml";
string xml = File.ReadAllText(xmlFile);
XmlSerializer serializer = new XmlSerializer(typeof(TABLE));
TABLE table = null;
using (var reader = new StringReader(xml))
{
table = (TABLE)serializer.Deserialize(reader);
}
}
Внутри объектов Min / Max / Source_code Value содержит значение, если оно присутствует (в этом случае Missing равно null), в противном случае Value равно null (в этом случае Missing содержит строку)
Рабочее решение на основе предложения jdweng
public class Compo {
public string alim_code { get; set; }
public string const_code { get; set; }
public string teneur { get; set; }
public string min { get; set; }
public string max { get; set; }
public string code_confiance { get; set; }
public string source_code { get; set; }
}
private void ReadCompoWithLinq() {
const string FILENAME = "test.xml";
XDocument doc = XDocument.Load(FILENAME);
List<Compo> compos = doc.Descendants("COMPO").Select(x => new Compo()
{
alim_code = (string)x.Element("alim_code"),
const_code = (string)x.Element("const_code"),
teneur = (string)x.Element("teneur"),
min = (x.Element("min").Attribute("missing") != null) ? null : (string)x.Element("min"),
max = (x.Element("max").Attribute("missing") != null) ? null : (string)x.Element("max"),
code_confiance = (string)x.Element("code_confiance"),
source_code = (x.Element("source_code").Attribute("missing") != null) ? null : (string)x.Element("source_code"),
}).ToList();
}
Объекты min, max, source_code содержат строковое значение, если оно предоставлено (в этом случае в описании XML используется атрибут "missing"), в противном случае строковое значение равно null.
Я пробовал код, но получаю исключение. Вероятно, это связано с тем, что я не упомянул, что блоки COMPO находятся внутри блока <TABLE> </TABLE> в файле XML.