XML LINQ语句几乎给出了预期的结果

时间:2014-01-03 16:46:35

标签: xml linq

我的情况需要其他一些眼睛。我有两个不同的XML文件,我通过LINQ语句来提供特定顺序的特定值,并且大多数情况下我都能正常工作。我缺少的只是其中一个部分的顺序,所以我希望有人可以在这里提供帮助。

我称之为模板的第一个文件:

<CARENetIn>
<transaction>
    <TimeStamp value="Fri Jan 03 07:57:39 CDT 2014" />
    <RequestCode value="ResetPassword" />
    <RetryCount value="0" />
    <ApplicationName value="CARE GENMED CLIENT" />
    <PlaylistName value="ResetPassword" />
</transaction>
<payload>
    <payloadItem name="LogonUserId">
        <value>CARE</value>
    </payloadItem>
    <payloadItem name="LogonPassword">
        <value>admin</value>
    </payloadItem>
    <payloadItem name="UserId">
        <value>HJones</value>
    </payloadItem>
    <payloadItem name="Password">
        <value>pass@word!</value>
    </payloadItem>
    <repeatedDataList>
        <repeatedItem>
            <payloadItem name="Test Key 1">
                <value>Test 1</value>
            </payloadItem>
            <payloadItem name="Test Key 2">
                <value>Test 2</value>
            </payloadItem>
        </repeatedItem>
        <repeatedItem>
            <payloadItem name="Test Key 1">
                <value>Test 3</value>
            </payloadItem>
            <payloadItem name="Test Key 2">
                <value>Test 4</value>
            </payloadItem>
        </repeatedItem>
    </repeatedDataList>
</payload>
</CARENetIn>

我称之为播放列表的第二个文件(删除某些部分的机密性,长度和清晰度):

<CARENet>
<CARENetID>
    <sequence>0</sequence>
</CARENetID>
<action type="SetText">
    <sequence>1</sequence>
    <fieldName>LogonUserId</fieldName>
</action>
<action type="SetText">
    <sequence>2</sequence>
    <fieldName>LogonPassword</fieldName>
</action>
<action type="PressButton">
    <sequence>3</sequence>
    <fieldName>Logon</fieldName>
</action>
<action type="TabSelect">
    <sequence>4</sequence>
    <fieldName>Modify</fieldName>
</action>
<action type="SetListBoxItem">
    <sequence>5</sequence>
    <fieldName>UserId</fieldName>
</action>
<action type="PressButton">
    <sequence>6</sequence>
    <fieldName>LoadUser</fieldName>
</action>
<action type="SetText">
    <sequence>7</sequence>
    <fieldName>Password</fieldName>
</action>
<action type="PressButton">
    <sequence>8</sequence>
    <fieldName>Update</fieldName>
</action>
<action type="SetText">
    <sequence>9</sequence>
    <fieldName>Test Key 1</fieldName>
</action>
<action type="SetListBoxItem">
    <sequence>10</sequence>
    <fieldName>GroupID</fieldName>
</action>
<action type="SetText">
    <sequence>11</sequence>
    <fieldName>Test Key 2</fieldName>
</action>
<action type="PressButton">
    <sequence>12</sequence>
    <fieldName>Exit</fieldName>
</action>
</CARENet>

现在,我有一个LINQ语句加入这两个列表,它们本质上应该获取所有值,并重复使用两者之间的action标记重复数据列表标记。以下是声明:

XDocument template = XDocument.Load(@"C:\CARE\Playlists\XML Repeated Test.xml");
XDocument playlist = XDocument.Load(@"C:\CARE\Playlists\RepeatedPlaylist.xml");

var action = from actionList in playlist.Descendants(XMLPlaylistAction.Root)
             join payloadList in template.Descendants(XMLIn.PayloadItem)
             on actionList.Descendants(XMLPlaylistAction.FieldName).First().Value.ToLower() equals
             payloadList.Attributes().First().Value.ToLower()
             into joined
             from subList in joined.DefaultIfEmpty()
             select new
             {
                 ID = (subList == null ? string.Empty : subList.Attributes().First().Value.ToString()),

                 Value = (subList == null ? string.Empty : subList.Elements().First().Value.ToString()),

                 Action = actionList.Attributes().First().Value.ToString()
             };

现在,当我循环播放它们的结果时,我得到了我需要的所有部分,并且大部分都按照正确的顺序。声明使用了FirstOrDefault而不是First,并且至少按顺序获得了重复值,但是这两个值之间有一个步骤,它显示在重复值之后。它需要每次都在重复的数据值中发生。

如何调整LINQ语句以显示重复值之间的步骤?

所以,只是为了澄清,结果看到了:

LogonUserID - SetText
LogonPassword - SetText
PressButton
TabSelect
UserId - SetListBoxItem
PressButton
Password - SetText
PressButton
TestKey1 - SetText
TestKey2 - SetText
TestKey1 - SetText
TestKey2 - SetText
SetListBoxItem
PressButton

我想看到的是:

LogonUserID - SetText
LogonPassword - SetText
PressButton
TabSelect
UserId - SetListBoxItem
PressButton
Password - SetText
PressButton
TestKey1 - SetText
SetListBoxItem
TestKey2 - SetText
TestKey1 - SetText
SetListBoxItem
TestKey2 - SetText
PressButton

我会很感激这里的任何想法。谢谢你们!

1 个答案:

答案 0 :(得分:1)

我的想法怎么样,虽然这不是最好的方法。

我使用struct MyResult而不是匿名类型。

public struct MyResult
{
    public string ID { get; set; }
    public string Value { get; set; }
    public string Action { get; set; }
    public int Sequence { get; set; }

    public override string ToString()
    {
        return (ID != null) ? string.Format("{0} - {1}", ID, Action) : Action;
    }
}

以下是获得所需结果的代码。

XDocument template = XDocument.Load(@"C:\CARE\Playlists\XML Repeated Test.xml");
XDocument playlist = XDocument.Load(@"C:\CARE\Playlists\RepeatedPlaylist.xml");

var listSrc = (from payloadList in template.Descendants("payloadItem")
            join actionList in playlist.Descendants("action")
            on payloadList.Attributes().First().Value.ToLower() equals
            actionList.Descendants("fieldName").First().Value.ToLower()
            select new MyResult
            {
                Sequence = int.Parse(actionList.Elements("sequence").First().Value),
                ID = payloadList.Attributes().First().Value,
                Value = payloadList.Elements().First().Value,
                Action = actionList.Attributes().First().Value
            }).ToList();

List<MyResult> listDst = new List<MyResult>();

listDst.Add(listSrc.First());

for (int i = 0; i < listSrc.Count() - 1; i++)
{
    if (listSrc[i].Sequence < listSrc[i + 1].Sequence)
    {
        for (int j = listSrc[i].Sequence + 1; j < listSrc[i + 1].Sequence; j++)
        {
            listDst.Add(new MyResult
            {
                Action = playlist.Descendants("action")
                .First(_ => _.Elements("sequence").First().Value == j.ToString())
                .Attributes().First().Value
            });
        }
    }
    listDst.Add(listSrc[i + 1]);
}
for (int i = listSrc.Last().Sequence; i <= int.Parse(playlist.Descendants("action").Elements("sequence").Last().Value); i++)
{
    listDst.Add(new MyResult
    {
        Action = playlist.Descendants("action")
        .First(_ => _.Elements("sequence").First().Value == i.ToString())
        .Attributes().First().Value
    });
}

foreach (var item in listDst)
{
    Console.WriteLine(item);
}