Is it just me? I find LINQ to XML to be sort of cu

2019-04-25 17:31发布

问题:

I am a C# programmer, so I don't get to take advantage of the cool XML syntax in VB.

Dim itemList1 = From item In rss.<rss>.<channel>.<item> _
                Where item.<description>.Value.Contains("LINQ") Or _
                      item.<title>.Value.Contains("LINQ")

Using C#, I find XPath to be easier to think about, easier to code, easier to understand, than performing a multi-nested select using LINQ to XML. Look at this syntax, it looks like Greek swearing:

var waypoints = from waypoint in gpxDoc.Descendants(gpx + "wpt") 
          select new 
          { 
            Latitude = waypoint.Attribute("lat").Value, 
            Longitude = waypoint.Attribute("lon").Value, 
            Elevation = waypoint.Element(gpx + "ele") != null ? 
                waypoint.Element(gpx + "ele").Value : null, 
            Name = waypoint.Element(gpx + "name") != null ? 
                waypoint.Element(gpx + "name").Value : null, 
            Dt = waypoint.Element(gpx + "cmt") != null ? 
                waypoint.Element(gpx + "cmt").Value : null 
          }; 

All the casting, the heavy syntax, the possibility for NullPointerExceptions. None of this happens with XPath.

I like LINQ in general, and I use it on object collections and databases, but my first go-round with querying XML led me right back to XPath.

Is it just me?

Am I missing something?


EDIT: someone voted to close this as "not a real question". But it is a real question, stated clearly. The question is: Am I misunderstanding something with LINQ to XML?

回答1:

Use what you feel the most comfortable with, as long as it gets the job done. I use both methods depending on what I need to do to with XML. It sounds to me like you've got a good handle on what LINQ is good for and what XPath is good for.



回答2:

Yes, the example you've given is unweildy.

But with LINQ comes the flexibility to refactor away the unweildiness.

Here's an example of how I would improve it. (This is done without any testing at all, and I don't even know the real class names, but it should convey the idea)

static class LinqXmlExtension
{
    public static NodeThingy ElementOrNull(this XmlElement ele, string searchString)
    {
         return (ele.Element(searchString) != null ? ele.Element(searchString).Value : null);
    }
}

//
/////////////////////////////////////////////////////////////////

var waypoints = from waypoint in gpxDoc.Descendants(gpx + "wpt")           
                select new           
                {             
                      Latitude  = waypoint.Attribute("lat").Value,             
                      Longitude = waypoint.Attribute("lon").Value,
                      Elevation = waypoint.ElementOrNull(gpx + "ele"),
                      Name      = waypoint.ElementOrNull(gpx + "name"),
                      Dt        = waypoint.ElementOrNull(gpx + "cmt")           
                 };


回答3:

I'm guessing at some of your data types, but you could make your C# LINQ query concise by casting your attribute values:

var waypoints =
    from waypoint in gpxDoc.Descendants(gpx + "wpt") 
    select new 
    { 
        Latitude = (decimal)waypoint.Attribute("lat"), 
        Longitude = (decimal)waypoint.Attribute("lon"), 
        Elevation = (decimal?)waypoint.Element(gpx + "ele"), 
        Name = (string)waypoint.Element(gpx + "name"), 
        Dt = (DateTime?)waypoint.Element(gpx + "cmt")
    };

And I'm sure you already know the @ syntax you can use for attributes in VB's XML literals.



回答4:

I can see your problem but I used LINQ for just reorder a GPX file to get trackpoints in every segment in the correct order and it feels rather straight forward.....

       var trksegs = doc.Root.Descendants(ns + "trkseg");
        foreach (var trkseg in trksegs)
        {
            List<XElement> trk = trkseg.Elements(ns + "trkpt")
                 .OrderBy(x => (string)x.Element(ns + "time")).ToList();
            trkseg.RemoveAll();
            trkseg.Add(trk);
        }

and also fix a bug in a delivered GPX file for time

  private static XDocument ConvertTimeElement(XDocument doc)
    {
        if (doc.Root != null)
        {
            var times = doc.Root.Descendants(ns + "time").ToList();
            foreach (var time in times)
                time.SetValue((string)ConvertSpotDateFormat(time));
        }
        return doc;
    }

I think it is rather straight format....

(The problem I fixed http://www.everytrail.com/forum/viewtopic.php?f=4&t=1980&p=6447#p6447)