Я работаю над преобразованием XML-файла в CSV с помощью C#. Я пробовал разные подходы, но не могу понять, как получить доступ к парам имя/значение ключа

#c# #xml

Вопрос:

Это базовый макет файла.

 <InvoiceNo>1065178</InvoiceNo>
<InstallationId>10903</InstallationId>
<CreateDate>2019-03-29T00:00:00</CreateDate>
<AccountNo>123456</AccountNo>
<BalanceDue>1024.40</BalanceDue>
<StatementDate>2019-04-01T00:00:00</StatementDate>
<NoPrint>0</NoPrint>
<Pages>
<Page templatepage="1">
<OtherFields>
<Key name="Instructions1"><Value>Please write your account number on your check!</Value></Key>
<Key name="AgeTitle1"><Value>CURRENT </Value></Key>
<Key name="AgeTitle2"><Value>30 DAYS </Value></Key>
<Key name="AgeTitle3"><Value>60 DAYS </Value></Key>
<Key name="AgeTitle4"><Value>90 DAYS </Value></Key>
</OtherFields>
</Page>
</Pages>
</Invoice>
 

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

 string xmlfile = @"C:/data//WDM/CUSTInvoiceData2019032902.xml";
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(xmlfile);


XmlNodeList nodelist = xmldoc.SelectNodes("//*[local-name()='OtherFields']");
Dictionary<string, string> dictXml = new Dictionary<string, string>();

foreach (XmlNode node in nodelist)
{
    foreach (XmlNode elementpair in node.ChildNodes)
    {
        dictXml.Add(elementpair.Attributes["Key name"].Value, 
        elementpair.Attributes["value"].Value);
    }
}
 

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

1. В стороне: что делать, если счет-фактура содержит несколько страниц?

2. Позвольте мне угадать: в XML много узлов счетов-фактур? И покажите, как должен выглядеть окончательный CSV-файл.

3. Существует нижний колонтитул, который помечает следующую страницу как продолжение, и это будет новая строка в csv-файле.

Ответ №1:

Используйте Сериализацию Xml

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication2
{
    class Program
    {
       const string FILE = @"c:TEMPTEST.XML";
       static void Main(string[] args)
        {
           XmlReader reader = XmlReader.Create(FILE);
           XmlSerializer serializer = new XmlSerializer(typeof(Invoice));
           Invoice invoice = (Invoice)serializer.Deserialize(reader);


        }
    }
    public class Invoice
    {
        public string InvoiceNo { get; set; }
        public string InstallationId { get; set; }
        public DateTime CreateDate { get; set; }
        public string AccountNo { get; set; }
        public decimal BalanceDue { get; set; }
        public DateTime StatementDate { get; set; }
        public int NoPrint { get; set; }

        [XmlArray("Pages")]
        [XmlArrayItem("Page")]
        public Page[] pages { get; set; }

    }
    public class Page
    {
        [XmlAttribute]
        public int templatepage { get; set; }

        [XmlArray("OtherFields")]
        [XmlArrayItem("Key")]
        public Key[] keys { get; set; }
    }
    public class Key
    {
        [XmlAttribute]
        public string name { get; set; }
        public Value  Value { get; set; }
    }
    public class Value
    {
        [XmlText]
        public string value { get; set; }
    }

}
  
 

введите описание изображения здесь

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

1. Попробуйте это, и я смогу перейти к счету — фактуре товаров верхнего уровня. Например, InvoiceNo, но я не смог получить доступ к массиву других полей?

2. Я добавил изображение выше. Все, что сделал Id, — это добавил в начале XML отсутствующий корневой тег<Счет-фактура>

Ответ №2:

Почти готово

  1. Вы ошибаетесь в имени атрибута не .Attributes["Key name"] но .Attributes["name"]
  2. Вы должны получить значение, а не атрибут, также вы должны получить значение дочерней заметки
     foreach (XmlNode elementpair in node.ChildNodes)
    {
        var key = elementpair.Attributes["name"].Value;
        var val = elementpair.ChildNodes[0].ChildNodes[0].Value;
        dictXml.Add(key,val);
    }
 

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

1. Спасибо за это, и это выглядело хорошо, пока я не столкнулся с пустым значением и не обнаружил, что я не могу иметь значение NULL в словаре без создания пользовательского словаря.

Ответ №3:

Вы выбираете Key элементы и ищете два атрибута: Key name и value . Но элементы не имеют атрибутов с этими именами. Ключ находится в вызываемом атрибуте name , а соответствующее значение находится в вызываемом дочернем элементе (не атрибуте) Value .

Ответ №4:

В вашем макете файла вы забыли добавить <Invoice> в начале.

И это более простой способ выполнения запроса. "//Key"

 XmlNodeList nodelist = xmldoc.SelectNodes("//Key");
Dictionary<string, string> dictXml = new Dictionary<string, string>();

foreach (XmlNode node in nodelist)
    dictXml[node.Attributes[0].Value] = node.InnerText;