对于后代中的循环(序列不包含元素)c#

时间:2017-07-10 06:19:39

标签: c# xml csv xml-parsing

我有一个复杂的XML文件,我想从特定的事务标记中检索值。最后,我需要将这些值转换为CSV文件。

Please see the xml file format

我正在尝试在每个事务标记中检索以下值。

<szCustomerID>2988880562567</szCustomerID>

   <szCustomerName>130808125028SHM </szCustomerName>

   <szExternalID>3177@06/07/17</szExternalID>

请注意,所有交易代码都不一样 不幸的是,它循环遍历所有事务标记,我得到的错误序列不包含任何元素

有没有办法可以循环使用后代,并且总是跳过第二个交易代码,因为我不需要它

  try
        {
            string strSource_voucher = @"C:\\TempFid";

                  string[] files = Directory.GetFiles(strSource_voucher, "*.xml", SearchOption.AllDirectories);

            if (files.Length > 0) // Check if files has values
            {
                StringBuilder dataToBeWritten = new StringBuilder();


                foreach (string file in files)
                {

                    dataToBeWritten.Append("szCustomerID");
                    dataToBeWritten.Append(",");
                    dataToBeWritten.Append("szCustomerName");
                    dataToBeWritten.Append(",");
                    dataToBeWritten.Append("szExternalID");
                    dataToBeWritten.Append(",");

                    dataToBeWritten.Append(Environment.NewLine);

                    XDocument xDocument = XDocument.Load(file);


                    int results = xDocument.Descendants("Transaction").Count();

                    foreach (var trans in xDocument.Descendants("Transaction"))

                    {
                           //var trans = xDocument.Descendants("Transaction");

                           var val1 = (string)trans.Descendants("Set").Elements("szCustomerID").First();

                            var val2 = (string)trans.Descendants("Set").Elements("szCustomerName").First();


                            var val3 = (string)trans.Descendants("Set").Elements("szExternalID").First();

                            dataToBeWritten.Append(val1);
                            dataToBeWritten.Append(",");

                            dataToBeWritten.Append(val2);
                            dataToBeWritten.Append(",");

                            dataToBeWritten.Append(val3);
                            dataToBeWritten.Append(",");

                            dataToBeWritten.Append(Environment.NewLine);


                    } // End of For each var trans


                    Console.WriteLine(dataToBeWritten.ToString());

                    Console.ReadLine();

3 个答案:

答案 0 :(得分:1)

您可以使用Element代替Elements并检查该值是否为null

foreach (var trans in xDocument.Descendants("Transaction"))
{
    XElement setElement = trans.Descendants("Set").FirstOrDefault();
    if (setElement != null)
    {
        var val1 = (string)setElement.Element("szCustomerID");
        var val2 = (string)setElement.Element("szCustomerName");
        var val3 = (string)setElement.Element("szExternalID");

        if (val1 != null && val3 != null && val3 != null)
        {
            dataToBeWritten.Append(val1);
            dataToBeWritten.Append(",");

            dataToBeWritten.Append(val2);
            dataToBeWritten.Append(",");

            dataToBeWritten.Append(val3);
            dataToBeWritten.Append(",");

            dataToBeWritten.Append(Environment.NewLine);
        }
    }
}

答案 1 :(得分:0)

只需使用for循环并将i增加2,如下所示:

var transactions = xDocument.Descendants("Transaction").ToList();
for (int i = 0; i < transactions.Count(); i += 2)
{

    //var trans = xDocument.Descendants("Transaction");
    var val1 = (string)transactions[i].Descendants("Set").Elements("szCustomerID").First();
    var val2 = (string)transactions[i].Descendants("Set").Elements("szCustomerName").First();
    var val3 = (string)transactions.Descendants("Set").Elements("szExternalID").First();

    dataToBeWritten.Append(val1);
    dataToBeWritten.Append(",");

    dataToBeWritten.Append(val2);
    dataToBeWritten.Append(",");

    dataToBeWritten.Append(val3);
    dataToBeWritten.Append(",");

    dataToBeWritten.Append(Environment.NewLine);
} // End of For each var trans

答案 2 :(得分:0)

如果您打开使用库(Cinchoo ETL - 开源ETL库),还有另一种方法可以进行此类转换

基于流,快速将任何xml转换为csv格式,只需几行代码。

我相信您希望仅从具有CUSTOMER表元素的xml中生成CSV文件。

以下是使用此库的方法

using (var parser = new ChoXmlReader("sample.xml").WithXPath("/UpdateDB/Transaction")
    .WithField("Table", xPath: "/Insert/Table")
    .WithField("szCustomerID", xPath: "/Insert/Set/szCustomerID")
    .WithField("szCustomerName", xPath: "/Insert/Set/szCustomerName")
    .WithField("szExternalID", xPath: "/Insert/Set/szExternalID")
    )
{
    using (var writer = new ChoCSVWriter("sample.csv").WithFirstLineHeader())
        writer.Write(parser.Where(r => r.Table == "CUSTOMER").Select(r => new { szCustomerID = r.szCustomerID, szCustomerName = r.szCustomerName, szExternalID = r.szExternalID }));
}

输出将如下所示

szCustomerID,szCustomerName,szExternalID
2988880562567,130808125028SHM,3177@06/07/17
12345,130808125028SHM,3177@06/07/17

<强>更新

为了将szExternalID拆分为2列(szExternalID,szExternalDate),您必须使用valueconverter来解析和加载它们。示例显示了如何

using (var parser = new ChoXmlReader("sample.xml").WithXPath("/UpdateDB/Transaction")
    .WithField("Table", xPath: "/Insert/Table")
    .WithField("szCustomerID", xPath: "/Insert/Set/szCustomerID")
    .WithField("szCustomerName", xPath: "/Insert/Set/szCustomerName")
    .WithField("szExternalID", xPath: "/Insert/Set/szExternalID", valueConverter: (v) => ((string)v).Split('@')[0])
    .WithField("szExternalDate", xPath: "/Insert/Set/szExternalID", valueConverter: (v) => ((string)v).Split('@')[1])
    )
{
    using (var writer = new ChoCSVWriter("sample.csv").WithFirstLineHeader())
        writer.Write(parser.Where(r => r.Table == "CUSTOMER").Select(r => new { szCustomerID = r.szCustomerID, szCustomerName = r.szCustomerName, szExternalID = r.szExternalID, szExternalDate = r.szExternalDate }));
}

新输出将如下所示

szCustomerID,szCustomerName,szExternalID,szExternalDate
2988880562567,130808125028SHM,3177,06/07/17
12345,130808125028SHM,3177,06/07/17

披露:我是这个图书馆的作者。