Reputation: 10765
I have the following code, which works by the way, but am working on making it shorter and using XML shorthand. All is fine thus far but is there a way to shorten the last few items, seems like an awful lot of Element calls:
Public Function ParseRates() As IEnumerable(Of RoomRate)
Try
For Each n As XElement In _xDoc...<_ns:RoomRate>
_rates.Add(New RoomRate With { _
.GuaranteeSurchargeRequired = n.@GuaranteeSurchargeRequired, _
.IATACharacteristicIdentification = n.@IATACharacteristicIdentification, _
.IATAProductIdentification = n.@IATAProductIdentification, _
.RPH = n.@RPH, _
.CancellationPolicy = n...<_ns:AdditionalInfo>.<_ns:CancelPolicy>.@Numeric, _
.Commission = n...<_ns:AdditionalInfo>.<_ns:Commission>.@NonCommission, _
.Rate = n.Element(_ns + "Rates").Element(_ns + "Rate").Attribute("Amount").Value, _
.CurrencyCode = n.Element(_ns + "Rates").Element(_ns + "Rate").Attribute("CurrencyCode").Value,
.TotalPrice = n.Element(_ns + "Rates").Element(_ns + "Rate").Element(_ns + "HotelTotalPricing").Attribute("Amount").Value, _
.Disclaimer = n.Element(_ns + "Rates").Element(_ns + "Rate").Element(_ns + "HotelTotalPricing").Element(_ns + "Disclaimer").Value, _
.Surcharge = n.Element(_ns + "Rates").Element(_ns + "Rate").Element(_ns + "HotelTotalPricing").Element(_ns + "TotalSurcharges").Attribute("Amount").Value})
Next
Return _rates
Catch ex As Exception
ErrorMessage = ex.Message
Return Nothing
End Try
End Function
Here's a snippet of the XML that's being parsed with said code
<HotelPropertyDescriptionRS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" TimeStamp="2013-12-30T18:49:36" Version="1.14.1">
<Success xmlns="http://webservices.sabre.com/sabreXML/2003/07" />
<RoomStay xmlns="http://webservices.sabre.com/sabreXML/2003/07">
<RoomRates>
<RoomRate GuaranteeSurchargeRequired="G" IATACharacteristicIdentification="BGGO00" IATAProductIdentification="BLOOMBERG" RPH="001">
<AdditionalInfo>
<CancelPolicy Numeric="06" />
<Commission NonCommission="true">NON COMMISSIONABLE</Commission>
<Text>BLOOMBERG LP, 0.0 KM, INCLUDES BREAKFAST, INTERNET, WIFI, SEE</Text>
<Text>RATE RULES DELUXE ROOM, GUEST ROOM, 1 KING OR 2 TWIN/SINGLE BE</Text>
</AdditionalInfo>
<Rates>
<Rate Amount="66.600" CurrencyCode="KWD">
<AdditionalGuestAmounts>
<AdditionalGuestAmount MaxExtraPersonsAllowed="0">
<Charges ExtraPerson="0" />
</AdditionalGuestAmount>
</AdditionalGuestAmounts>
<HotelTotalPricing Amount="76.590">
<Disclaimer>INCLUDES TAXES AND SURCHARGES</Disclaimer>
<TotalSurcharges Amount="9.990" />
</HotelTotalPricing>
</Rate>
</Rates>
</RoomRate>
</RoomRates>
</HotelPropertyDescriptionRS>
Upvotes: 0
Views: 86
Reputation: 125650
How about using AddRange
and LINQ query inside it?
You can use Let
to simplify your query a little:
Dim query = From n In _xDoc...<_ns:RoomRate>
Let additionalInfo = n...<_ns:AdditionalInfo>
Let rate = n.<_ns:Rates>.<_ns:Rate>
Let hotelPricing = rate.<_ns:HotelTotalPricing>
Select New RoomRate With {
.GuaranteeSurchargeRequired = n.@GuaranteeSurchargeRequired, _
.IATACharacteristicIdentification = n.@IATACharacteristicIdentification, _
.IATAProductIdentification = n.@IATAProductIdentification, _
.RPH = n.@RPH, _
.CancellationPolicy = additionalInfo.<_ns:CancelPolicy>.@Numeric, _
.Commission = additionalInfo.<_ns:Commission>.@NonCommission, _
.Rate = rate.@Amount, _
.CurrencyCode = rate.@CurrencyCode,
.TotalPrice = hotelPricing.@Amount, _
.Disclaimer = hotelPricing.<_ns:Disclaimer>.Value, _
.Surcharge = hotelPricing.<_ns:TotalSurcharges>.@Amount
}
It requires namespace import declaration:
Imports <xmlns:_ns="test">
and you should be able to call AddRange
on _rates
:
_rates.AddRange(query)
Upvotes: 1
Reputation: 89315
Speaking about this part :
.Rate = n.Element(_ns + "Rates").Element(_ns + "Rate").Attribute("Amount").Value, _
.CurrencyCode = n.Element(_ns + "Rates").Element(_ns + "Rate").Attribute("CurrencyCode").Value,
.TotalPrice = n.Element(_ns + "Rates").Element(_ns + "Rate").Element(_ns + "HotelTotalPricing").Attribute("Amount").Value, _
.Disclaimer = n.Element(_ns + "Rates").Element(_ns + "Rate").Element(_ns + "HotelTotalPricing").Element(_ns + "Disclaimer").Value, _
.Surcharge = n.Element(_ns + "Rates").Element(_ns + "Rate").Element(_ns + "HotelTotalPricing").Element(_ns + "TotalSurcharges").Attribute("Amount").Value})
there are some other ways to get those 5 values. First, using .Descendants()
and get the first element returned :
.Rate = n.Descendants(_ns + "Rate").First().Attribute("Amount").Value, _
.CurrencyCode = n.Descendants(_ns + "Rate").First().Attribute("CurrencyCode").Value,
.TotalPrice = n.Descendants(_ns + "HotelTotalPricing").First().Attribute("Amount").Value, _
.Disclaimer = n.Descendants(_ns + "Disclaimer").First().Value, _
.Surcharge = n.Descendants(_ns + "TotalSurcharges").First().Attribute("Amount").Value})
.Descendants()
can bring you any child of current element when Element()
only search direct child of current element. Other option is by using XPath :
.Rate = n.XPathSelectElement(".//n:Rate", nsm).Attribute("Amount").Value, _
.CurrencyCode = n.XPathSelectElement(".//n:Rate", nsm).Attribute("CurrencyCode").Value,
.TotalPrice = n.XPathSelectElement(".//n:HotelTotalPricing", nsm).Attribute("Amount").Value, _
.Disclaimer = n.XPathSelectElement(".//n:Disclaimer", nsm).Value, _
.Surcharge = n.XPathSelectElement(".//n:TotalSurcharges", nsm).Attribute("Amount").Value
in this case, you need to define prefix to be used in XPath expression first :
Dim nsm As XmlNamespaceManager = New XmlNamespaceManager(New NameTable)
nsm.AddNamespace("n", "http://webservices.sabre.com/sabreXML/2003/07")
And add Imports
:
Imports System.Xml.XPath
Switching from method style to XPath is simple. This is basics about XPath syntax :
.
) in fornt of expression tell to search from current node. Without it expression will be evaluated from root node//
) is analog to Descendants()
/
) is analog to Element()
or Elements()
Upvotes: 1