用c# LINQ解析复杂的XML

本文关键字:复杂 XML LINQ | 更新日期: 2023-09-27 18:14:14

我在VS2012的脚本转换中使用c#和LINQ来解析复杂的xml soap消息。我不知道如何遍历xml并在一行中获得我想要的所有元素。xml如下所示。这只是返回内容的一部分。每项48个间隔,一般为5-6项。

<return>
<item>
    <interval>
        <intervalDate>
            <day>8</day>
            <month>7</month>
            <year>2016</year>
        </intervalDate>
        <intervalTime>
            <hours>0</hours>
            <militaryTime>true</militaryTime>
            <minutes>0</minutes>
            <seconds>0</seconds>
        </intervalTime>
        <laborType>forecasted</laborType>
        <volume>0.0</volume>
    </interval>
    <interval>
        <intervalDate>
            <day>8</day>
            <month>7</month>
            <year>2016</year>
        </intervalDate>
        <intervalTime>
            <hours>0</hours>
            <militaryTime>true</militaryTime>
            <minutes>30</minutes>
            <seconds>0</seconds>
        </intervalTime>
        <laborType>forecasted</laborType>
        <volume>0.0</volume>
    </interval>
    <jobCode>1</jobCode>
    <jobName>SERVER</jobName>
</item>
<item>
    <interval>
        <intervalDate>
            <day>8</day>
            <month>7</month>
            <year>2016</year>
        </intervalDate>
        <intervalTime>
            <hours>0</hours>
            <militaryTime>true</militaryTime>
            <minutes>0</minutes>
            <seconds>0</seconds>
        </intervalTime>
        <laborType>forecasted</laborType>
        <volume>0.0</volume>
    </interval>
    <interval>
        <intervalDate>
            <day>8</day>
            <month>7</month>
            <year>2016</year>
        </intervalDate>
        <intervalTime>
            <hours>0</hours>
            <militaryTime>true</militaryTime>
            <minutes>30</minutes>
            <seconds>0</seconds>
        </intervalTime>
        <laborType>forecasted</laborType>
        <volume>0.0</volume>
    </interval>
    <jobCode>50</jobCode>
    <jobName>Cashier</jobName>
</item>

我需要将数据输出为5列,datetime, laborType, laborVolume, laborJobCode和laborJobName。

laborDateTime | laborType | laborVolume | laborJobCode | laborJobName

2016-08-07 00:00:00.000 |预测| 0 | 1 |服务器

2016-08-07 00:30:00.000 |预测| 0 | 1 |服务器

2016-08-07 01:00:00.000 |预测| 0 | 1 |服务器

2016-08-07 01:30:00.000 |预测| 0 | 1 |服务器

我没能在网上找到任何例子来展示如何做到这一点。如果循环Interval,则返回预期的行数,但无法获得JobCode和JobName。

    public override void CreateNewOutputRows()
{
    /*
      Add rows by calling the AddRow method on the member variable named "<Output Name>Buffer".
      For example, call MyOutputBuffer.AddRow() if your output was named "MyOutput".
    */
    String content = Variables.XMLString;
    XElement xdoc = XElement.Parse(content);
    var Interval = from interval in xdoc.Descendants("interval")
                   select new
                   {
                             laborIntervalDay = interval.Element("intervalDate").Element("day").Value,
                             laborIntervalMonth = interval.Element("intervalDate").Element("month").Value,
                             laborIntervalYear = interval.Element("intervalDate").Element("year").Value,
                             laborIntervalHour = interval.Element("intervalTime").Element("hours").Value,
                             laborIntervalMinutes = interval.Element("intervalTime").Element("minutes").Value,
                             laborIntervalSeconds = interval.Element("intervalTime").Element("seconds").Value,
                             laborIntervalMilitary = interval.Element("intervalTime").Element("militaryTime").Value,
                             laborType = interval.Element("laborType").Value,
                             laborVolume = interval.Element("volume").Value
                   };

            foreach (var q in Interval)
            {
                try
                {
                    DateTime dtBusinessDate = new DateTime(Convert.ToInt32(q.laborIntervalYear), Convert.ToInt32(q.laborIntervalMonth), Convert.ToInt32(q.laborIntervalDay), Convert.ToInt32(q.laborIntervalHour), Convert.ToInt32(q.laborIntervalMinutes), Convert.ToInt32(q.laborIntervalSeconds));
                    OUTLaborBuffer.AddRow();
                    OUTLaborBuffer.laborDateTime = dtBusinessDate;
                    OUTLaborBuffer.laborType = Convert.ToString(q.laborType);
                    OUTLaborBuffer.laborVolume = Convert.ToDouble(q.laborVolume);
                    //OUTLaborBuffer.laborJobCode = Convert.ToInt64(p.laborJobCode);
                    //OUTLaborBuffer.laborJobName = p.laborJobName;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error Message: " + ex.Message + " Message Detail: " + ex.StackTrace);
                }
            }
    }

我也尝试过通过Labor和Interval循环,但这是不正确的,因为它将当前Labor迭代的JobCode/JobName分配给所有间隔。如果有5个项目,那么我最终得到预期行数的5倍。

        var Interval = from interval in xdoc.Descendants("interval")
                   select new
                   {
                             laborIntervalDay = interval.Element("intervalDate").Element("day").Value,
                             laborIntervalMonth = interval.Element("intervalDate").Element("month").Value,
                             laborIntervalYear = interval.Element("intervalDate").Element("year").Value,
                             laborIntervalHour = interval.Element("intervalTime").Element("hours").Value,
                             laborIntervalMinutes = interval.Element("intervalTime").Element("minutes").Value,
                             laborIntervalSeconds = interval.Element("intervalTime").Element("seconds").Value,
                             laborIntervalMilitary = interval.Element("intervalTime").Element("militaryTime").Value,
                             laborType = interval.Element("laborType").Value,
                             laborVolume = interval.Element("volume").Value
                   };
    var Labor = from item in xdoc.Descendants("item")
                         select new
                         {
                             laborJobCode = item.Element("jobCode").Value,
                             laborJobName = item.Element("jobName").Value,
                         };
    foreach (var p in Labor)
    {
        // Save check information
        try
        {
            foreach (var q in Interval)
            {
                try
                {
                    DateTime dtBusinessDate = new DateTime(Convert.ToInt32(q.laborIntervalYear), Convert.ToInt32(q.laborIntervalMonth), Convert.ToInt32(q.laborIntervalDay), Convert.ToInt32(q.laborIntervalHour), Convert.ToInt32(q.laborIntervalMinutes), Convert.ToInt32(q.laborIntervalSeconds));
                    OUTLaborBuffer.AddRow();
                    OUTLaborBuffer.laborDateTime = dtBusinessDate;
                    OUTLaborBuffer.laborType = Convert.ToString(q.laborType);
                    OUTLaborBuffer.laborVolume = Convert.ToDouble(q.laborVolume);
                    OUTLaborBuffer.laborJobCode = Convert.ToInt64(p.laborJobCode);
                    OUTLaborBuffer.laborJobName = p.laborJobName;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error Message: " + ex.Message + " Message Detail: " + ex.StackTrace);
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error Message: " + ex.Message + " Message Detail: " + ex.StackTrace);
        }
    }

}

我在网上发现了一些复杂xml被解析的例子,如下所示:

        var Labor = from item in xdoc.Descendants("item")
                         select new
                         {
                             laborJobCode = item.Element("jobCode").Value,
                             laborJobName = item.Element("jobName").Value,
                             laborInterval = (from interval in xdoc.Descendants("interval")
                                              select new
                                              {
                                                laborIntervalDay = interval.Element("intervalDate").Element("day").Value,
                                                laborIntervalMonth = interval.Element("intervalDate").Element("month").Value,
                                                laborIntervalYear = interval.Element("intervalDate").Element("year").Value,
                                                laborIntervalHour = interval.Element("intervalTime").Element("hours").Value,
                                                laborIntervalMinutes = interval.Element("intervalTime").Element("minutes").Value,
                                                laborIntervalSeconds = interval.Element("intervalTime").Element("seconds").Value,
                                                laborIntervalMilitary = interval.Element("intervalTime").Element("militaryTime").Value,
                                                laborType = interval.Element("laborType").Value,
                                                laborVolume = interval.Element("volume").Value
                                              })
                         };

我用这个结构找到的例子是输出ToList,我不知道如何以这种格式输出interval的后代。你知道该怎么做吗?

用c# LINQ解析复杂的XML

类似这样的代码应该可以达到这个效果:

    public dynamic OUTLaborBuffer;
    public dynamic Variables;
    public void CreateNewOutputRows()
    {
        String content = Variables.XMLString;
        XElement data = XElement.Parse(content);
        foreach (var item in data.XPathSelectElements("//item"))
        {
            var jobCode = item.Element("jobCode").Value;
            var jobName = item.Element("jobName").Value;
            foreach (var interval in item.XPathSelectElements("//interval"))
            {
                var laborIntervalDay = interval.Element("intervalDate").Element("day").Value;
                var laborIntervalMonth = interval.Element("intervalDate").Element("month").Value;
                var laborIntervalYear = interval.Element("intervalDate").Element("year").Value;
                var laborIntervalHour = interval.Element("intervalTime").Element("hours").Value;
                var laborIntervalMinutes = interval.Element("intervalTime").Element("minutes").Value;
                var laborIntervalSeconds = interval.Element("intervalTime").Element("seconds").Value;
                var laborIntervalMilitary = interval.Element("intervalTime").Element("militaryTime").Value;
                var laborType = interval.Element("laborType").Value;
                var laborVolume = interval.Element("volume").Value;
                DateTime dtBusinessDate = new DateTime(Convert.ToInt32(laborIntervalYear), Convert.ToInt32(laborIntervalMonth), Convert.ToInt32(q.laborIntervalDay), Convert.ToInt32(laborIntervalHour), Convert.ToInt32(laborIntervalMinutes), Convert.ToInt32(laborIntervalSeconds));
                OUTLaborBuffer.AddRow();
                OUTLaborBuffer.laborDateTime = dtBusinessDate;
                OUTLaborBuffer.laborType = Convert.ToString(laborType);
                OUTLaborBuffer.laborVolume = Convert.ToDouble(laborVolume);
                OUTLaborBuffer.laborJobCode = Convert.ToInt64(jobCode);
                OUTLaborBuffer.laborJobName = jobName;
            }
        }
    }

可以随意将XPathSelectElements更改回Descendants

我可以通过在循环间隔时使用parent来获取JobCode和JobName来解决这个问题。我基于这个例子:Linq on Complex XML

下面是我最后写的代码:
public override void CreateNewOutputRows()
{
    /*
      Add rows by calling the AddRow method on the member variable named "<Output Name>Buffer".
      For example, call MyOutputBuffer.AddRow() if your output was named "MyOutput".
    */
    String content = Variables.XMLString;
    XElement xdoc = XElement.Parse(content);
    var Interval = from interval in xdoc.Descendants("interval")
                   select new
                   {
                       laborJobCode = interval.Parent.Element("jobCode").Value,
                       laborJobName = interval.Parent.Element("jobName").Value,
                       laborIntervalDay = interval.Element("intervalDate").Element("day").Value,
                       laborIntervalMonth = interval.Element("intervalDate").Element("month").Value,
                       laborIntervalYear = interval.Element("intervalDate").Element("year").Value,
                       laborIntervalHour = interval.Element("intervalTime").Element("hours").Value,
                       laborIntervalMinutes = interval.Element("intervalTime").Element("minutes").Value,
                       laborIntervalSeconds = interval.Element("intervalTime").Element("seconds").Value,
                       laborIntervalMilitary = interval.Element("intervalTime").Element("militaryTime").Value,
                       laborType = interval.Element("laborType").Value,
                       laborVolume = interval.Element("volume").Value
                   };
    foreach (var q in Interval) 
        {
            try
                {
                    DateTime dtBusinessDate = new DateTime(Convert.ToInt32(q.laborIntervalYear), Convert.ToInt32(q.laborIntervalMonth), Convert.ToInt32(q.laborIntervalDay), Convert.ToInt32(q.laborIntervalHour), Convert.ToInt32(q.laborIntervalMinutes), Convert.ToInt32(q.laborIntervalSeconds));
                    OUTLaborBuffer.AddRow();
                    OUTLaborBuffer.laborDateTime = dtBusinessDate;
                    OUTLaborBuffer.laborType = Convert.ToString(q.laborType);
                    OUTLaborBuffer.laborVolume = Convert.ToDouble(q.laborVolume);
                    OUTLaborBuffer.laborJobCode = Convert.ToInt64(q.laborJobCode);
                    OUTLaborBuffer.laborJobName =  Convert.ToString(q.laborJobName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error Message: " + ex.Message + " Message Detail: " + ex.StackTrace);
                }
            }
        }