在LINQ中的语句(如果没有值做某事......)

时间:2013-03-26 17:02:35

标签: c# linq linq-to-xml

我试图制作一个显示丛林的应用程序,包括公交车号码,目标小时和预计小时。

我从HttpWebRequest获取了我的(实时)信息。我对请求的响应以XML格式存储在字符串变量中。

我可以得到我想要的所有信息;比如公共汽车时间,瞄准时间和预计时间。

问题是,如果没有预期的时间,将不会显示任何内容。我希望当没有预期的小时时,我的代码只需要与目标小时相同的值:

一个例子

Bus | Aimed | Execepted
-----------------------
1   | 17:05 | 17:07
2   | 17:05 | <nothing> so take value of aimed -> 17:05

我已经有以下代码

//XMLResponse put in documentRoot
//responseFromServer is a string variable in XML format with all the information
XElement documentRoot = XDocument.Parse(responseFromServer).Root;
XNamespace ns = "http://www.siri.org.uk/";

var buses = (from tblBuses in documentRoot.Descendants(ns + "PublishedLineName")
             select tblBuses.Value).ToList();
var expHours = (from tblHours in documentRoot.Descendants(ns + "ExpectedDepartureTime")
               select tblHours.Value).ToList();

foreach (var bus in buses)
{
    string output = bus.Substring(bus.IndexOf('T') + 1);
    int index = output.IndexOf(".");

    if (index > 0)
        output = output.Substring(0, index);

    listBox1.Items.Add("Bus: " + output);
}


//Show every ExpectedDepartureTime
//If there is no expectedTime take value AimedDepartureTime
foreach (var expH in expHours)
{
    string output = expH.Substring(expH.IndexOf('T') + 1);
    int index = output.IndexOf(".");

    if (index > 0)
        output = output.Substring(0, index);

    lstHours.Items.Add(output);
}

更清楚地了解我的XML响应,下面是我的XML响应示例(一个是AimedDeparturetime和Expected,一个是没有预期的)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Siri version="1.0" xmlns="http://www.siri.org.uk/">
<ServiceDelivery>
<ResponseTimestamp>2013-03-26T16:09:48.181Z</ResponseTimestamp>
<StopMonitoringDelivery version="1.0">
<ResponseTimestamp>2013-03-26T16:09:48.181Z</ResponseTimestamp>
<RequestMessageRef>12345</RequestMessageRef>

<MonitoredStopVisit>
<RecordedAtTime>2013-03-26T16:09:48.181Z</RecordedAtTime>
<MonitoringRef>020035811</MonitoringRef>
<MonitoredVehicleJourney>
<FramedVehicleJourneyRef>
<DataFrameRef>-</DataFrameRef>
<DatedVehicleJourneyRef>-</DatedVehicleJourneyRef>
</FramedVehicleJourneyRef>
<VehicleMode>bus</VehicleMode>
<PublishedLineName>2</PublishedLineName>
<DirectionName>Elstow P+R</DirectionName>
<OperatorRef>STB</OperatorRef>
<MonitoredCall>
<AimedDepartureTime>2013-03-26T16:11:00.000Z</AimedDepartureTime>
<ExpectedDepartureTime>2013-03-26T16:11:28.000Z</ExpectedDepartureTime>
</MonitoredCall>
</MonitoredVehicleJourney>
</MonitoredStopVisit>
---------------------------------------------------

<MonitoredStopVisit>
<RecordedAtTime>2013-03-26T16:09:48.181Z</RecordedAtTime>
<MonitoringRef>020035811</MonitoringRef>
<MonitoredVehicleJourney>
<FramedVehicleJourneyRef>
<DataFrameRef>-</DataFrameRef>
<DatedVehicleJourneyRef>-</DatedVehicleJourneyRef>
</FramedVehicleJourneyRef>
<VehicleMode>bus</VehicleMode>
<PublishedLineName>53</PublishedLineName>
<DirectionName>Wootton</DirectionName>
<OperatorRef>STB</OperatorRef>
<MonitoredCall>
<AimedDepartureTime>2013-03-26T16:19:00.000Z</AimedDepartureTime>
</MonitoredCall>
</MonitoredVehicleJourney>
</MonitoredStopVisit>
</StopMonitoringDelivery>
</ServiceDelivery>
</Siri>

所以在这一刻我的申请并没有显示公共汽车的每个出发时间。

我该如何解决这个问题?

谢谢!

2 个答案:

答案 0 :(得分:3)

道歉,因为这不是最好的XML解析,但我会调整我的LINQ查询:

var buses = from tblBuses in documentRoot.Descendants(ns + "MonitoredVehicleJourney")
            select new
                   {
                       LineName = tblBuses.Descendants(ns + "PublishedLineName").Single().Value,
                       AimedHours = tblBuses.Descendants(ns + "AimedDepartureTime").Single().Value,
                       ExpectedHours = tblBuses.Descendants(ns + "ExpectedDepartureTime").Select(el => el.Value).SingleOrDefault()
                   };

这将创建一个匿名类型的IEnumerable,允许您在后续代码中更轻松地访问总线数据:

foreach (var bus in buses)
{
    // Take ExpectedHours, or AimedHours if the first is null
    string expH = bus.ExpectedHours ?? bus.AimedHours

    // Same code as before here
    string output = expH.Substring(expH.IndexOf('T') + 1);
    int index = output.IndexOf(".");
    if (index > 0)
        output = output.Substring(0, index);
    lstHours.Items.Add(output);
}

在原始代码中,没有<ExpectedDepartureTime>的总线从未迭代过,因为它们从未出现在expHours列表中。相反,此LINQ查询将包含所有总线。它假定它们都有一个<AimedDepartureTime>和一个可选的<ExpectedDepartureTime>

对于预期的出发时间,我使用Select来获取每个后代的元素值。无法使用SingleOrDefault().Value,因为查询可能不会生成任何元素,get_Value()引用会调用null

关于我的查询的最后一条评论:对于生产代码,我将避免使用Descendants并对XML结构进行更严格的查询。

答案 1 :(得分:2)

您可以在一个linq查询中执行所有操作,并使用?:条件运算符来选择正确的输出:

var buses = 
    (from tblBuses in documentRoot.Descendants(ns + "PublishedLineName")
     let bus = tblBuses.Value
     let output = bus.Substring(bus.IndexOf('T') + 1)
     let index = output.IndexOf(".")
     select (index > 0) ? output.Substring(0, index) : output);

foreach (var bus in buses)
{
    listBox1.Items.Add("Bus: " + bus);
}

甚至

var buses =
    (from ...
     select "Bus: " + ((index > 0) ? output.Substring(0, index) : output));
    .ToArray();

listBox1.Items.AddRange(buses);

相同的模式可以应用于expHours