Reputation: 10755
I have an incoming XML stream from a web service response that looks like so
<?xml version="1.0" encoding="utf-16"?>
<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>
....
(there will be many RoomRate values returned. I have created a class to hold the values I need to parse from said XML which looks like so
Namespace Classes.Models
Public Class RoomRate
Public Property Rate() As String
Public Property Surcharge() As String
Public Property TotalPrice() As String
Public Property CurrencyCode() As String
Public Property CancellationPolicy() As String
Public Property Disclaimer() As String
Public Property Text() As List(Of String)
Public Property Commission() As String
Public Property GuaranteeSurchargeRequired() As String
Public Property IATACharacteristicIdentification() As String
Public Property IATAProductIdentification() As String
Public Property RPH() As String
End Class
End Namespace
Now I'm not looking for someone to write all the code for me, I'm more looking for ideas on which would be the most efficient way to parse this into my class. I can use the XPathDocument and XPathNavigation & XPathNodeIterator classes to do this (not 100% sure how they work yet) but is there a better way to accomplish this task?
EDIT
I have come up with this so far, which should get me the first attributes in the RoomRate element
Return From el As XElement In _xDoc...<RoomRate>
Select New RoomRate With { _
.GuaranteeSurchargeRequired = el...<RoomRate>.@GuaranteeSurchargeRequired, _
.IATACharacteristicIdentification = el...<RoomRate>.@IATACharacteristicIdentification, _
.IATAProductIdentification = el...<RoomRate>.@IATAProductIdentification, _
.RPH = el...<RoomRate>.@RPH}
Now how would I traverse to get say the cancellation policy, room rate and other attributes/elements within this code I provided? Sorry for so many questions, I really want to learn this the right way and be able to do it correctly.
EDIT #2
I think I'm on the right track here:
Return From el As XElement In _xDoc...<RoomRate>
Select New RoomRate With { _
.GuaranteeSurchargeRequired = el.@GuaranteeSurchargeRequired, _
.IATACharacteristicIdentification = el.@IATACharacteristicIdentification, _
.IATAProductIdentification = el.@IATAProductIdentification, _
.RPH = el.@RPH, _
.CancellationPolicy = el...<AdditionalInfo>...<CancellationPolicy>.@Numeric, _
.Commission = el...<AdditionalInfo>...<Commission>.@NonCommission}
Can someone let me know if I'm on the right track for accomplishing this?
EDIT 3
I have changed my code to this
For Each n As XElement In _xDoc.Elements("RoomRate")
_rates.Add(New RoomRate With { _
.GuaranteeSurchargeRequired = n.Attribute("GuarateeSurchargeRequired").Value, _
.IATACharacteristicIdentification = n.Attribute("IATACharacteristicIdentification").Value, _
.IATAProductIdentification = n.Attribute("IATAProductIdentification").Value, _
.RPH = n.Attribute("RPH")})
Next
And while I'm no longer getting any errors, but am not getting any results returned as well.
EDIT 4 I have made the following changes t my code, which should return an IEnumerable(Of RoomRate) but it's returning nothing (this is based on the XML snippet i posted above)
Dim rates = From rate In _xDoc.Descendants("RoomRate")
Select New RoomRate With { _
.GuaranteeSurchargeRequired = rate.Attribute("GuaranteeSurchargeRequired").Value, _
.IATACharacteristicIdentification = rate.Attribute("IATACharacteristicIdentification").Value, _
.IATAProductIdentification = rate.Attribute("IATAProductIdentification").Value, _
.RPH = rate.Attribute("RPH").Value}
That looks like it should work, what am I doing wrong here?
EDIT #5 @Neolisk I made my changes the way you suggested, it now looks like so
For Each n As XElement In _xDoc.Descendants("RoomRate")
rate = New RoomRate()
rate.GuaranteeSurchargeRequired = n.Attribute("GuaranteeSurchargeRequired").Value
rate.IATACharacteristicIdentification = n.Attribute("IATACharacteristicIdentification").Value
rate.IATAProductIdentification = n.Attribute("IATAProductIdentification")
_rates.Add(rate)
Next
Return _rates
But it never goes into the loop, it goes straight to Return _rates
EDIT #6
Ok I got it populating the first 3 attributes of the RoomRate element like this
Dim rate As RoomRate
Dim ns As XNamespace = "http://webservices.sabre.com/sabreXML/2003/07"
Dim rate As RoomRate
For Each n As XElement In _xDoc.Descendants(ns + "RoomRate")
rate = New RoomRate()
rate.GuaranteeSurchargeRequired = n.Attribute("GuaranteeSurchargeRequired").Value
rate.IATACharacteristicIdentification = n.Attribute("IATACharacteristicIdentification").Value
rate.IATAProductIdentification = n.Attribute("IATAProductIdentification").Value
rate.RPH = n.Attribute("RPH").Value
_rates.Add(rate)
Next
Now when I try to traverse through the rest of the document I try and get the CancelPolicy value like so
Dim rate As RoomRate
Dim ns As XNamespace = "http://webservices.sabre.com/sabreXML/2003/07"
Dim rate As RoomRate
For Each n As XElement In _xDoc.Descendants(ns + "RoomRate")
rate = New RoomRate()
rate.GuaranteeSurchargeRequired = n.Attribute("GuaranteeSurchargeRequired").Value
rate.IATACharacteristicIdentification = n.Attribute("IATACharacteristicIdentification").Value
rate.IATAProductIdentification = n.Attribute("IATAProductIdentification").Value
rate.RPH = n.Attribute("RPH").Value
rate.CancellationPolicy = n.Element("AdditionalInfo").Element("CancelPolicy").Attribute("Numeric").Value
_rates.Add(rate)
Next
But adding that last line causes a NullReferenceException. How would I go about going through the XML now?
Upvotes: 0
Views: 2402
Reputation: 10755
Got my issue resolved with this code
Public Function ParseRates() As IEnumerable(Of RoomRate)
Try
Dim ns As XNamespace = "http://webservices.sabre.com/sabreXML/2003/07"
Dim rate As RoomRate
For Each n As XElement In _xDoc.Descendants(ns + "RoomRate")
_rates.Add(New RoomRate With { _
.GuaranteeSurchargeRequired = n.Attribute("GuaranteeSurchargeRequired").Value, _
.IATACharacteristicIdentification = n.Attribute("IATACharacteristicIdentification").Value, _
.IATAProductIdentification = n.Attribute("IATAProductIdentification").Value, _
.RPH = n.Attribute("RPH").Value, _
.CancellationPolicy = n.Element(ns + "AdditionalInfo").Element(ns + "CancelPolicy").Attribute("Numeric").Value, _
.Commission = n.Element(ns + "AdditionalInfo").Element(ns + "Commission").Attribute("NonCommission").Value, _
.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
Maybe someday I'll find a more efficient way to accomplish this
Upvotes: 1
Reputation: 26424
If you've never dealt with LINQ to XML, you may find yourself struggling a bit at the beginning, but this should help you get there faster:
Dim xml As XDocument = XDocument.Parse("...") 'or XDocument.Load("...")
You can also assign a whole XML (or part thereof) into a variable AS IS, to test your concept, i.e. this is 100% valid syntax in VB10+ (~.NET 4.0+):
Dim xml As XDocument = <?xml version="1.0" encoding="utf-16"?>
<RoomRates>
<RoomRate>
<AdditionalInfo>
<Text>BLOOMBERG LP, 0.0 KM</Text>
</AdditionalInfo>
<Rates>
<Rate Amount="66.600" CurrencyCode="KWD"></Rate>
</Rates>
</RoomRate>
</RoomRates>
After that, here is what you can do:
Dim ns As XNamespace = "http://webservices.sabre.com/sabreXML/2003/07"
Dim roomRate As XElement = xml.Descendants(ns + "RoomRate").First
Dim additionalInfoText As String = roomRate.Descendants(ns + "Text").First
You can now inspect both roomRate
and additionalInfoText
in debugger, to see how it worked.
When in doubt about functionality of XDocument/XElement
, please see relevant MSDN articles.
Upvotes: 0