Great Big Al
Great Big Al

Reputation: 582

LINQ XML - Select all parent elements where a child has a given value

From the XML below, I need to find information about all flights where FlightSegmentReference ref equals BA2759, and then pass some details from the parent elements to a class

 If Len(inFlightNo) > 0 Then
     Dim xdoc As XDocument = XDocument.Parse(rawXML)
     Dim results As IEnumerable(Of Offer) =
         From offer In xdoc.Descendants(myns + "FlightSegmentReference")
             Where offer.Attribute("ref") = inFlightNo
                 Select New Offer With
                 {.FlightRef = offer.Attribute("ref")}
     'Return results
 End If

This example works fine... however I need to get more data to pass to my class, such as TotalAmount SimpleCurrancyPrice and OfferItemID

 If Len(inFlightNo) > 0 Then
     Dim xdoc As XDocument = XDocument.Parse(rawXML)
     Dim results As IEnumerable(Of Offer) =
         From offer In xdoc.Descendants(myns + "FlightSegmentReference")
             Where offer.Attribute("ref") = inFlightNo
                 Select New Offer With
                 {.FlightRef = offer.Attribute("ref"),
                  .Price = ????,
                  .OfferItemID = ????
                 }
     'Return results
 End If

What is the best practice method of getting SimpleCurrencyPrice and populating Price in my class

Here is the XML

<AirlineOffers>
   <TotalOfferQuantity>1156</TotalOfferQuantity>
   <Owner>BA</Owner>
   <AirlineOffer RequestedDateInd="true">
      <OfferID Owner="BA">OFFER1</OfferID>
      <TotalPrice>
         <SimpleCurrencyPrice Code="GBP">129.50</SimpleCurrencyPrice>
      </TotalPrice>
      <PricedOffer>
         <OfferPrice OfferItemID="1">
            <RequestedDate>
               <PriceDetail>
                  <TotalAmount>
                     <SimpleCurrencyPrice Code="GBP">129.50</SimpleCurrencyPrice>
                  </TotalAmount>
                  <BaseAmount Code="GBP">84.00</BaseAmount>
                  <Taxes>
                     <Total Code="GBP">45.50</Total>
                  </Taxes>
               </PriceDetail>
               <Associations>
                  <AssociatedTraveler>
                     <TravelerReferences>SH1</TravelerReferences>
                  </AssociatedTraveler>
               </Associations>
            </RequestedDate>
         </OfferPrice>
         <Associations>
            <ApplicableFlight>
               <FlightSegmentReference ref="BA2759">
                  <ClassOfService>
                     <Code>O</Code>
                     <MarketingName>Euro Traveller</MarketingName>
                  </ClassOfService>
               </FlightSegmentReference>
            </ApplicableFlight>
            <PriceClass>
               <PriceClassReference>Plus</PriceClassReference>
            </PriceClass>
         </Associations>
         <Associations>
            <ApplicableFlight>
               <FlightSegmentReference ref="BA2764">
                  <ClassOfService>
                     <Code>Q</Code>
                     <MarketingName>Euro Traveller</MarketingName>
                  </ClassOfService>
               </FlightSegmentReference>
            </ApplicableFlight>
            <PriceClass>
               <PriceClassReference>Plus</PriceClassReference>
            </PriceClass>
         </Associations>
      </PricedOffer>
   </AirlineOffer>
   <AirlineOffer RequestedDateInd="true">
      <OfferID Owner="BA">OFFER2</OfferID>
      <TotalPrice>
         <SimpleCurrencyPrice Code="GBP">129.50</SimpleCurrencyPrice>
      </TotalPrice>
      <PricedOffer>
         <OfferPrice OfferItemID="1">
            <RequestedDate>
               <PriceDetail>
                  <TotalAmount>
                     <SimpleCurrencyPrice Code="GBP">129.50</SimpleCurrencyPrice>
                  </TotalAmount>
                  <BaseAmount Code="GBP">84.00</BaseAmount>
                  <Taxes>
                     <Total Code="GBP">45.50</Total>
                  </Taxes>
               </PriceDetail>
               <Associations>
                  <AssociatedTraveler>
                     <TravelerReferences>SH1</TravelerReferences>
                  </AssociatedTraveler>
               </Associations>
            </RequestedDate>
         </OfferPrice>
         <Associations>
            <ApplicableFlight>
               <FlightSegmentReference ref="BA2765">
                  <ClassOfService>
                     <Code>O</Code>
                     <MarketingName>Euro Traveller</MarketingName>
                  </ClassOfService>
               </FlightSegmentReference>
            </ApplicableFlight>
            <PriceClass>
               <PriceClassReference>Plus</PriceClassReference>
            </PriceClass>
         </Associations>
         <Associations>
            <ApplicableFlight>
               <FlightSegmentReference ref="BA2764">
                  <ClassOfService>
                     <Code>Q</Code>
                     <MarketingName>Euro Traveller</MarketingName>
                  </ClassOfService>
               </FlightSegmentReference>
            </ApplicableFlight>
            <PriceClass>
               <PriceClassReference>Plus</PriceClassReference>
            </PriceClass>
         </Associations>
      </PricedOffer>
   </AirlineOffer>
</AirlineOffers>

Upvotes: 0

Views: 379

Answers (2)

ocuenca
ocuenca

Reputation: 39386

I'm not a VB developer but I think is easy what I going to propose, instead of select FlightSegmentReference nodes, select PricedOffer which is the element that have all the info you need, so it would be:

Dim results As IEnumerable(Of Offer) =
      From offer In xdoc.Descendants(myns + "PricedOffer")
      Where offer.Descendants(myns +"FlightSegmentReference")
                  .Any(Function(e) e.Attribute("ref").Value = inFlightNo)
      Select New Offer() With {
                          .FlightRef = inFlightNo,
                          .Price = offer.Descendants(myns +"SimpleCurrencyPrice").FirstOrDefault().Value
                          .OfferItemID =offer.Element(myns +"OfferPrice").Attribute("OfferItemID").Value 
}

Upvotes: 2

Mark
Mark

Reputation: 8160

You could use Parent to navigate back up the tree from the FlightSegmentReference element:

Dim results As IEnumerable(Of Offer) =
    From ref In xdoc.Descendants(myns + "FlightSegmentReference")
    Where ref.Attribute("ref") = inFlightNo
    Let offer = ref.Parent.Parent.Parent.Parent
    Select New Offer With {
        .FlightRef = ref.Attribute("ref"),
        .Price = CDec(offer.Element(myns + "TotalPrice").Element(myns + "SimpleCurrencyPrice").Value),
        .OfferItemID = offer.Element(myns + "PricedOffer").Element(myns + "OfferPrice").Attribute("OfferItemID")
    }

I like using VB.NET's XML syntax support - it seems more readable to me, although you will need to Import your namespace:

Dim results2 As IEnumerable(Of Offer) =
    From e In xdoc...<myns:FlightSegmentReference>
    Where e.@ref = inFlightNo
    Let offer = e.Parent.Parent.Parent.Parent
    Select New Offer() With {
        .FlightRef = e.@ref,
        .Price = CDec(offer.<myns:TotalPrice>.<myns:SimpleCurrencyPrice>.Value),
        .OfferItemID = offer.<myns:PricedOffer>.<myns:OfferPrice>.@OfferItemID
    }

Upvotes: 0

Related Questions