Search code examples
vb.netparsingxmlconvert

Parsing Size and Position Objects from an XmlDocument?


Is there more elegant syntax for reading/parsing Size and Point objects in an Xml document?

Source Xml Nodes:

<objSize>{Width=64, Height=64}</objSize>
<Location_X>20</Location_X>
<Location_Y>20</Location_Y>

Currently I use: For Size:

   Dim sizeNode As String = objSize.InnerText
   Dim sizeText() As String = sizeNode.Split(CChar("="))
   Dim width As Integer = XmlConvert.ToInt32(sizeText(1).Split(CChar(","))(0))
   Dim height As Integer = XmlConvert.ToInt32(sizeText(2).TrimEnd(CChar("}")))
   Dim newSize as New Size(width, height)

For Point:

Dim newLocation As Point
newLocation = New Point(XmlConvert.ToInt32(objNode.InnerText), newLocation.Y)
newLocation = New Point(newLocation.X, XmlConvert.ToInt32(objNode.InnerText))

I have a nagging feeling like I am missing something? I have control over both the source nodes and the parsing code... So I am just being too lazy with my XmlNode creation? Regardless is there any benefit to using XmlConvert v.s. using integer.parse (or .tryparse)?


Solution

  • If you control the format, then a better approach would be to decompose size into two elements, or an element with attributes, e.g.:

    <objSize Width="64" Height="64"/>
    

    I'd do the same for location - not that it matters much, but it looks neater, and emphasizes that it is a single data point better:

    <Location X="20" Y="20"/>
    

    The difference between XmlConvert and Parse is that the former uses very specific rules for parsing, which are those from XML Schema specification. For Int32, I believe there's no difference.

    One other way you can deal with typed nodes is to validate your XML against a schema (where you'd specify that all those elements and/or attributes are of type xs:int), and then use XPathNavigator.TypedValue. E.g.:

     Dim doc As XmlDocument
     doc.Load(...)
     doc.Schemas.Add(Nothing, "my_schema.xsd")
     doc.Validate()
    
     ....
    
     Dim sizeNode As XmlNode = ...
     Dim sizeNodeNav = sizeNode.CreateNavigator()
     ' Validation performed above ensures that value returned
     ' by TypedValue below will be of expected type
     Dim width = CType(sizeNodeNav.SelectSingleNode("@Width").TypedValue, Integer)
     Dim height = CType(sizeNodeNav.SelectSingleNode("@Height").TypedValue, Integer)
    

    Alternatively, you can use XPathNaigator.ValueAsInt() method and skip the validation:

     Dim width = sizeNodeNav.SelectSingleNode("@Width").ValueAsInt
    

    All those ways use XmlConvert internally, however.

    Also, if your document is sufficiently well-structured, you might just want to use XmlSerializer to parse it into a strongly typed object graph - it will handle all conversions for you.