Results 1 to 10 of 10

Thread: [RESOLVED] Navigating through XML

  1. #1

    Thread Starter
    Fanatic Member InvisibleDuncan's Avatar
    Join Date
    May 2001
    Location
    Eating jam.
    Posts
    819

    Resolved [RESOLVED] Navigating through XML

    I've got the following XML document that contains application settings:

    Code:
    <?xml version="1.0" encoding="utf-8" ?>
    <Environment>
    
      <Live>
          <Database>LiveDB</Database>
          <Server>LiveServer</Server>
          <UserID>LiveID</UserID>
          <Password>LivePassword</Password>
          <DatabaseType>System.Data.SqlClient</DatabaseType>
      </Live>
    
      <UAT>
        <Database>UATDB</Database>
        <Server>UATServer</Server>
        <UserID>UATID</UserID>
        <Password>UATPassword</Password>
        <DatabaseType>System.Data.SqlClient</DatabaseType>
      </UAT>
    
      <Development>
        <Database>DevDB</Database>
        <Server>DevServer</Server>
        <UserID>DevID</UserID>
        <Password>DevPassword</Password>
        <DatabaseType>System.Data.SqlClient</DatabaseType>
      </Development>
    
    </Environment>
    I can get things at the end of a chain reasonably simply. For example, this code:

    Code:
                Dim xpathDoc As XPathDocument = New XPathDocument("C\SettingsDocument.xml")
                Dim xmlNav As XPathNavigator = xpathDoc.CreateNavigator()
                Dim xmlNI As XPathNodeIterator
    
                xmlNI = xmlNav.Select("/Environment/UAT/Database")
                While xmlNI.MoveNext()
                    MessageBox.Show(xmlNI.Current.Value)
                End While
    ... will return "UATDB". Easy.

    The problem is that I'd like to get hold of a list of the environments, i.e. Live, UAT and Development. I had imagined that using the above code but swapping out the line
    Code:
    xmlNI = xmlNav.Select("/Environment/UAT/Database")
    for
    Code:
    xmlNI = xmlNav.Select("/Environment")
    would do it, but it doesn't - it basically retuns a string of all the end values: "LiveDBLiveServerLiveIDLivePasswordSystem.Data.SqlClientUATDBUATServerUATIDUATPasswordSystem.Data.Sq lClientDevDBDevServerDevIDDevPasswordSystem.Data.SqlClient". Not helpful.

    So, does anyone know how I can get a list of the those environments out of that XML?

    Much obliged.
    Indecisiveness is the key to flexibility.

    www.mangojacks.com

  2. #2
    Frenzied Member MattP's Avatar
    Join Date
    Dec 2008
    Location
    WY
    Posts
    1,227

    Re: Navigating through XML

    Here's a couple of ways of going about it. I normally go about it using the methods shown in dev2 or dev3 depending on whether I need to have a strongly typed variable or whether an anonymous type will work.

    vb.net Code:
    1. Public Class Form1
    2.  
    3.     Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4.  
    5.         'Load xml file into XDocument
    6.         Dim xdoc = XDocument.Load("C:\Temp\Environment.xml")
    7.  
    8.         'Select XElements from xdoc
    9.         Dim selectedNodes = (From n In xdoc.<Environment>
    10.                             Select n.<Live>, n.<UAT>, n.<Development>).FirstOrDefault()
    11.  
    12.         'Strongly typed from selectedNodes.Development
    13.         Dim dev = (From n In selectedNodes.Development
    14.                   Select New Development With
    15.                          {
    16.                              .Database = n.<Database>.Value,
    17.                              .Server = n.<Server>.Value,
    18.                              .UserId = n.<UserID>.Value,
    19.                              .DevPassword = n.<Password>.Value,
    20.                              .DatabaseType = n.<DatabaseType>.Value
    21.                          }).FirstOrDefault()
    22.  
    23.         'Strongly typed from xdoc's descendant <Development>
    24.         Dim dev2 = (From n In xdoc...<Development>
    25.                    Select New Development With
    26.                           {
    27.                               .Database = n.<Database>.Value,
    28.                               .Server = n.<Server>.Value,
    29.                               .UserId = n.<UserID>.Value,
    30.                               .DevPassword = n.<Password>.Value,
    31.                               .DatabaseType = n.<DatabaseType>.Value
    32.                           }).FirstOrDefault()
    33.  
    34.         'Anonymous type rather than using Development class
    35.         Dim dev3 = (From n In xdoc...<Development>
    36.                     Select New With
    37.                           {
    38.                               .Database = n.<Database>.Value,
    39.                               .Server = n.<Server>.Value,
    40.                               .UserId = n.<UserID>.Value,
    41.                               .DevPassword = n.<Password>.Value,
    42.                               .DatabaseType = n.<DatabaseType>.Value
    43.                           }).FirstOrDefault()
    44.     End Sub
    45. End Class
    46.  
    47. Public Class Development
    48.     Public Property Database As String
    49.     Public Property Server As String
    50.     Public Property UserId As String
    51.     Public Property DevPassword As String
    52.     Public Property DatabaseType As String
    53. End Class
    This pattern in common to all great programmers I know: they're not experts in something as much as experts in becoming experts in something.

    The best programming advice I ever got was to spend my entire career becoming educable. And I suggest you do the same.

  3. #3
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Navigating through XML

    I'd probably lay out the XML a little different from the start...
    Code:
    <Environments>
      <Environment Name="Live">
          <Database>LiveDB</Database>
          <Server>LiveServer</Server>
          <UserID>LiveID</UserID>
          <Password>LivePassword</Password>
          <DatabaseType>System.Data.SqlClient</DatabaseType>
      </Environment>
    ...
    </Environments>
    Or even

    Code:
    <Environments>
      <Environment Name="Live" Datablase="LiveDB" Server="LiveServer" UserID="LiveID" Password="LivePassword" Type="System.Data.SqlClient" />
    ...
    </Environments>
    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  4. #4
    Code Monkey wild_bill's Avatar
    Join Date
    Mar 2005
    Location
    Montana
    Posts
    2,993

    Re: Navigating through XML

    I would use XML serialization.
    Code:
    Option Strict On
    Option Explicit On
    
    Imports System.Xml.Serialization
    
    Namespace DataBase
    
        <XmlRoot("Environment")> _
        Public Class Environments
    
            Public Development As Information
            Public Live As Information
            Public UAT As Information
    
        End Class
    
        Public Class Information
    
            Public Database As String
            Public Server As String
            Public UserID As String
            Public Password As String
            Public DatabaseType As String
    
        End Class
    
    End Namespace
    Code:
        Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
            'get data from file
            Dim xmlData = IO.File.ReadAllText("C:\temp1\Environment.xml")
            'create object from data
            Dim o = DeserializeFromString(xmlData)
    
        End Sub
    
        Private Function DeserializeFromString(ByVal input As String) As DataBase.Environments
    
            'Convert to byte array
            Dim encoding As New System.Text.UTF8Encoding
            Dim bytes() As Byte = encoding.GetBytes(input)
    
            'read bytes into stream
            Dim ms As New System.IO.MemoryStream
            ms.Write(bytes, 0, bytes.Length)
            ms.Position = 0
    
            'get object from bytes
            Dim xs As New Xml.Serialization.XmlSerializer(GetType(DataBase.Environments))
            Return DirectCast(xs.Deserialize(ms), DataBase.Environments)
    
        End Function
    That is the very essence of human beings and our very unique capability to perform complex reasoning and actually use our perception to further our understanding of things. We like to solve problems. -Kleinma

    Does your code in post #46 look like my code in #45? No, it doesn't. Therefore, wrong is how it looks. - jmcilhinney

  5. #5

    Thread Starter
    Fanatic Member InvisibleDuncan's Avatar
    Join Date
    May 2001
    Location
    Eating jam.
    Posts
    819

    Re: Navigating through XML

    Thanks for all the advice, folks. Unfortunately, MattP's code is for 2010 and Bill's seems to need me to already know what the possible environments are, when the problem is that I won't know until I extract them from the XML. It's quite possible I've misunderstood, though.

    I've tweaked the XML slightly (not quite as suggested by TG), and I've now been able to do what I was after:

    Code:
    <Environments>
      <Environment>
          <EnvironmentName>Live</EnvironmentName>
          <Database>LiveDB</Database>
          <Server>LiveServer</Server>
          <UserID>LiveID</UserID>
          <Password>LivePassword</Password>
          <DatabaseType>System.Data.SqlClient</DatabaseType>
      </Environment>
    ...
    </Environments>
    Code:
        Public Shared Function GetEnvironments() As List(Of String)
            Dim Environments As List(Of String) = New List(Of String)
    
            Try
                '# Our configuration file holds properties based on the environment.
                '# Return a list of these environments.
                Dim xmlDoc = XDocument.Load(SettingsDocument)
    
                For Each EnvironmentXML In xmlDoc...<Environment>
                    Environments.Add(EnvironmentXML...<EnvironmentName>.Value)
                Next
    
                Return Environments
    
            Catch ex As Exception
                WriteLog(ex)
                Return Environments
            End Try
    
        End Function
    The only problem is, I now can't do something which I could with the original layout - that is, to find a specific element while using a variable:
    Code:
        Public Shared Function GetApplicationSetting(ByVal settingName As String) As String
    
            Dim Setting As String = String.Empty
            Try
                '# Setting is held in the configuration file as a global setting.
                Dim xpathDoc As XPathDocument = New XPathDocument(SettingsDocument)
                Dim xmlNav As XPathNavigator = xpathDoc.CreateNavigator()
                Dim xmlNI As XPathNodeIterator
    
                xmlNI = xmlNav.Select("/Environment/Global/" & settingName)
                While xmlNI.MoveNext()
                    Setting = xmlNI.Current.Value
                End While
    
                Return Setting
    
            Catch ex As Exception
                WriteLog(ex)
                Return Setting
            End Try
    
        End Function
    Stepping though this shows that it steps straight out of the loop, meaning that there's no .MoveNext to be performed. The xmlNI.Current.Value is back to being "LiveDBLiveServerLiveIDLivePasswordSystem.Data.SqlClientUATDBUATServerUATIDUATPasswordSystem.Data.Sq lClientDevDBDevServerDevIDDevPasswordSystem.Data.SqlClient".

    I think I'm just making matters worse!
    Indecisiveness is the key to flexibility.

    www.mangojacks.com

  6. #6

    Thread Starter
    Fanatic Member InvisibleDuncan's Avatar
    Join Date
    May 2001
    Location
    Eating jam.
    Posts
    819

    Re: Navigating through XML

    By the way, I can obviously see why that old code isn't working - I just can't see what I need to change it to.
    Indecisiveness is the key to flexibility.

    www.mangojacks.com

  7. #7

    Thread Starter
    Fanatic Member InvisibleDuncan's Avatar
    Join Date
    May 2001
    Location
    Eating jam.
    Posts
    819

    Re: Navigating through XML

    Okay, I've managed to get something working having rejigged my XML as suggested by TG.

    Code:
            Try
    
                Dim xmlDoc As Xml.XmlDocument = New Xml.XmlDocument
                xmlDoc.Load(SettingsDocument)
    
                Dim MainNodes As Xml.XmlNodeList = xmlDoc.GetElementsByTagName("Environment")
    
                For Each ChildNode As Xml.XmlNode In MainNodes
                    Debug.Print(ChildNode.Attributes.GetNamedItem("Name").Value) '# Environment name: Live, UAT etc
                    For Each InnerNode As XmlNode In ChildNode.ChildNodes
                        Debug.Print(InnerNode.LocalName & " = " & InnerNode.InnerText) '# Element, e.g. UserID = LiveUserID
                    Next InnerNode
                Next ChildNode
    
            Catch ex As Exception
            End Try
    It's a little clumsy as it needs to loop through to find everything rather than jumping to the correct node to start with, but at least it works.
    Indecisiveness is the key to flexibility.

    www.mangojacks.com

  8. #8
    Frenzied Member MattP's Avatar
    Join Date
    Dec 2008
    Location
    WY
    Posts
    1,227

    Re: Navigating through XML

    Quote Originally Posted by InvisibleDuncan View Post
    Unfortunately, MattP's code is for 2010
    It should work under 2008 with the addition of underscores at the line breaks.

    Glad you got a solution that works for you though.
    This pattern in common to all great programmers I know: they're not experts in something as much as experts in becoming experts in something.

    The best programming advice I ever got was to spend my entire career becoming educable. And I suggest you do the same.

  9. #9

    Thread Starter
    Fanatic Member InvisibleDuncan's Avatar
    Join Date
    May 2001
    Location
    Eating jam.
    Posts
    819

    Re: Navigating through XML

    Thanks, Matt - I hadn't realised that. I think I might investigate your suggestion a bit more, because it looks very interesting and completely different to what I've tried before. I'm all for learning something new.

    In the meantime, I did find a simple way of getting at individual elements:
    Code:
            Dim xmlDoc As Xml.XmlDocument = New Xml.XmlDocument
            xmlDoc.Load(SettingsDocument)
    
            Dim MainNodes As Xml.XmlNodeList = xmlDoc.SelectNodes("/Environments/Environment[@Name='Development']")
    
            For Each ChildNode As Xml.XmlNode In MainNodes
                Debug.Print(ChildNode.Attributes.GetNamedItem("Name").Value) '# Environment name: Live, UAT etc
                Debug.Print(ChildNode.SelectSingleNode("Database").InnerXml)
                Debug.Print(ChildNode.SelectSingleNode("Server").InnerXml)
                Debug.Print(ChildNode.SelectSingleNode("UserID").InnerXml)
                Debug.Print(ChildNode.SelectSingleNode("Password").InnerXml)
            Next ChildNode
    Thanks to everyone for their help - it's much appreciated.
    Indecisiveness is the key to flexibility.

    www.mangojacks.com

  10. #10
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: [RESOLVED] Navigating through XML

    yeah, you shouldn't have to loop through the nodes to find the one you want... you really only need to loop when you want them all, or not sure what you're looking for... the xQuery you have there should be perfect, and would be how I'd roll with it too ... until someone like Matt comes along and points out the LINQ version, and I'd go "oh sweet!" and then re-write everything... :P

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width