XML Question

All the XML I have seen recently is about getting a NodesList and for any node, getting an attribute

Faced with a document like this, how do I get the Value of the DESCRIPTION node from each TEMPLATE in the file, and also the other items, so that I can create objects of a class from each?

32mm Round (F1A) 22 22 30 48mm Round (F1A)

Well this is pretty sloppy and there needs to be a lot of error checking done, etc., but it should get you started. I actually have helper routines where I can select a child based on its name, rather than just by number…it’s based on the for-next loop in the following code.

  dim s as String = "<TEMPLATES><TEMPLATE><DESCRIPTION>32mm Round (F1A)</DESCRIPTION><WIDTH>22</WIDTH><HEIGHT>22</HEIGHT></TEMPLATE><TEMPLATE><HEIGHT>30</HEIGHT><DESCRIPTION>48mm Round (F1A)</DESCRIPTION></TEMPLATE></TEMPLATES>"

//Set the xml document
  dim xml as new XmlDocument(s)
  
  dim tagName as String = "DESCRIPTION"

//Set the main variable as the first child, otherwise you won't find the DESCRIPTION node, only two TEMPLATE nodes.
  dim main as XmlNode = xml.FirstChild
  
  //Loop through the TEMPLATE nodes
  dim node as XmlNode
  for i as integer = 0 to main.childCount -1
    node = main.Child(i)
    //Loop through the nodes in each TEMPLATE node
    for j as Integer = 0 to node.ChildCount-1
      //If this node's name is tagName (set as DESCRIPTION above)
      if node.child(j).Name = tagname then
        MsgBox node.Child(j).FirstChild.Value
      end if
    next j
  next i

Thanks.
Thats got me started.
Astonishing there is no GetNode( < name> ) method.
It means I have to iterate through all the elements to see if there is one I like.
Or use XQL to get a NodesList which I don’t really want.

Thanks for your help. I have a working solution based on this.

XQL is the easy and more robust way to do this IMHO.

I forgot about XQL, but I have been updating my routines to use it. I guess it’s been a while since I looked at this stuff. Heh. Anyway, I don’t know about robust, but it is more elegant.

  dim s as String = "<TEMPLATES><TEMPLATE><DESCRIPTION>32mm Round (F1A)</DESCRIPTION><WIDTH>22</WIDTH><HEIGHT>22</HEIGHT></TEMPLATE><TEMPLATE><HEIGHT>30</HEIGHT><DESCRIPTION>48mm Round (F1A)</DESCRIPTION></TEMPLATE></TEMPLATES>"
  dim xml as new XmlDocument(s)
  
  //Get descriptions from each template separately
  dim xql as XmlNodeList = xml.Xql("TEMPLATES/TEMPLATE")
  for i as Integer = 0 to xql.Length - 1
    dim descriptions as XmlNodeList = xql.Item(i).xql("DESCRIPTION")
    for j as Integer = 0 to descriptions.Length - 1
      MsgBox descriptions.Item(j).FirstChild.Value
    next j
  next i
  
  //or you can get ALL the descriptions in one shot
  xql = xml.Xql("TEMPLATES/TEMPLATE/DESCRIPTION")
  for i as Integer = 0 to xql.Length - 1
    MsgBox xql.Item(i).ToString
  next i

+1 on XQL

+1 too on XQL. I make heavy use of it. Never let me down yet. Trap any errors when it gets malformed/corrupt XML tho.

Full disclosure: I actually use a combination of XQL and get-value-by-name. I use XQL to get the top-level tags - TEMPLATE in the OP’s example. Then I pick out the individual values with a method like

Function XMLvalue(node as XmlNode, fld() as string) As string
  dim s as string
  dim i as integer
  
  for i= 1 to ubound(fld)
    if node= nil then exit
    node= XMLitem(node, fld(i))
  next
  
  if node<> nil then
    if node.ChildCount= 1 and node.FirstChild isa XmlTextNode then
      s= node.FirstChild.value
    end
  end
  
  return s
End Function

Function XMLitem(node as XMLNode, name as string) As XMLNode
  dim i as integer
  
  if node<> nil then
    for i= 0 to node.ChildCount-1
      if node.child(i).name= name then
        return node.child(i)
      end
    next
  end
  
  return nil
  
End Function

Hit post too soon and can’t edit.

You call it like

dim nodelist as XMLNodeList = doc.xql....
dim node as XMLNode = nodelist.item(x)
dim s as string = XMLValue(node, "tag", "subtag", "sub-sub-tag")

Oops, I dropped the paramarray in the method signature

Function XMLvalue(node as XmlNode, paramarray fld() as string) As string

You can nest the tags as deep as you need.