Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. LINQ
  4. XML to object using LINQ, using different constructors depending on data

XML to object using LINQ, using different constructors depending on data

Scheduled Pinned Locked Moved LINQ
helpcsharplinqlinuxxml
3 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    Cesa37
    wrote on last edited by
    #1

    I am parsing an XML with data I want to convert to objects of an already existing class (so I don't want to modify the class itself). There is a specific sub-element that each element may or may not have, and depending on whether that sub-element exists, I want to use a different object constructor in my select clause. This is how I did it (both code and xml are simplified):

    <channel>
    <display-name>SVT Europa</display-name>
    </channel>
    <channel>
    <display-name>Eurosport</display-name>
    <icon src="http://whatever" />
    </channel>

    var channels =
    (
    //Icon URL is not required so the LINQ is divided into two parts, first get channels with an icon URL.
    from x in channelsXml.Root.Elements("channel")
    where
    x.Element("icon") != null &&
    x.Element("icon").Attribute("src") != null &&
    Uri.IsWellFormedUriString(x.Element("icon").Attribute("src").Value, UriKind.RelativeOrAbsolute)
    select new Channel(
    x.Element("display-name").Value,
    new Uri(x.Element("icon").Attribute("src").Value)
    )
    )
    //Secondly, add channels missing an icon URL.
    .Concat(
    from x in channelsXml.Root.Elements("channel")
    where
    x.Element("icon") == null ||
    x.Element("icon").Attribute("src") == null
    select new Channel(
    x.Element("display-name").Value
    )
    );

    Is this a good way to do it? My primary concern is whether the collection of "channel" elements is searched twice, and if there is a solution to the problem where it isn't. I also don't think it's very readable, hence the comments, is there a "cleaner" way to do it? (Remember that I simplified the code and xml, in the actual code several more elements are read, and a lot more error checking are handled in the where clauses, and a lot of the error checking is duplicated because of the .Concat) Comments? Insights? I'm new at LINQ so feel free to bash my way of using it if you like ;)

    G 1 Reply Last reply
    0
    • C Cesa37

      I am parsing an XML with data I want to convert to objects of an already existing class (so I don't want to modify the class itself). There is a specific sub-element that each element may or may not have, and depending on whether that sub-element exists, I want to use a different object constructor in my select clause. This is how I did it (both code and xml are simplified):

      <channel>
      <display-name>SVT Europa</display-name>
      </channel>
      <channel>
      <display-name>Eurosport</display-name>
      <icon src="http://whatever" />
      </channel>

      var channels =
      (
      //Icon URL is not required so the LINQ is divided into two parts, first get channels with an icon URL.
      from x in channelsXml.Root.Elements("channel")
      where
      x.Element("icon") != null &&
      x.Element("icon").Attribute("src") != null &&
      Uri.IsWellFormedUriString(x.Element("icon").Attribute("src").Value, UriKind.RelativeOrAbsolute)
      select new Channel(
      x.Element("display-name").Value,
      new Uri(x.Element("icon").Attribute("src").Value)
      )
      )
      //Secondly, add channels missing an icon URL.
      .Concat(
      from x in channelsXml.Root.Elements("channel")
      where
      x.Element("icon") == null ||
      x.Element("icon").Attribute("src") == null
      select new Channel(
      x.Element("display-name").Value
      )
      );

      Is this a good way to do it? My primary concern is whether the collection of "channel" elements is searched twice, and if there is a solution to the problem where it isn't. I also don't think it's very readable, hence the comments, is there a "cleaner" way to do it? (Remember that I simplified the code and xml, in the actual code several more elements are read, and a lot more error checking are handled in the where clauses, and a lot of the error checking is duplicated because of the .Concat) Comments? Insights? I'm new at LINQ so feel free to bash my way of using it if you like ;)

      G Offline
      G Offline
      Gideon Engelberth
      wrote on last edited by
      #2

      This looks like a job for the ternary operator. You can check for the existence of the attribute in the select statement as the condition of a ternary operator. I also pulled the condition out to a separate function just because it seemed a bit large for a ternary condition and figured it would be easier to read.

      from x in channelsXml.Root.Elements("channel")
      select HasIcon(x) ?
      new Channel(x.Element("display-name").Value,
      new Uri(x.Element("icon").Attribute("src").Value)
      ) :
      new Channel(x.Element("display-name").Value);

      bool HasIcon(XElement x)
      {
      return x.Element("icon") != null &&
      x.Element("icon").Attribute("src") != null &&
      Uri.IsWellFormedUriString(x.Element("icon").Attribute("src").Value, UriKind.RelativeOrAbsolute);
      }

      C 1 Reply Last reply
      0
      • G Gideon Engelberth

        This looks like a job for the ternary operator. You can check for the existence of the attribute in the select statement as the condition of a ternary operator. I also pulled the condition out to a separate function just because it seemed a bit large for a ternary condition and figured it would be easier to read.

        from x in channelsXml.Root.Elements("channel")
        select HasIcon(x) ?
        new Channel(x.Element("display-name").Value,
        new Uri(x.Element("icon").Attribute("src").Value)
        ) :
        new Channel(x.Element("display-name").Value);

        bool HasIcon(XElement x)
        {
        return x.Element("icon") != null &&
        x.Element("icon").Attribute("src") != null &&
        Uri.IsWellFormedUriString(x.Element("icon").Attribute("src").Value, UriKind.RelativeOrAbsolute);
        }

        C Offline
        C Offline
        Cesa37
        wrote on last edited by
        #3

        Much nicer, thank you!

        1 Reply Last reply
        0
        Reply
        • Reply as topic
        Log in to reply
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes


        • Login

        • Don't have an account? Register

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • World
        • Users
        • Groups