• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 474
  • Last Modified:

Put key / value array into XML document

Hi

I've got an class that is serialized to XML (containing other classes) a bit like this.

The "tag" field is unique.
The "value" field contains values to use in calculations. The "value" field is populated by client system which can only provide an array of tag/values like this

Tag       Value
000A    999
000B    23
300      123

<Data>
  <Class1>
     <FieldA tag="000A" value="?"    ...other attributes... >
             <AnotherClass>
                    <FieldX tag="100" value="?" ...other attributes... />
                    <FieldY tag="200" value="?" ...other attributes... />
                    <FieldZ tag="300" value="?" ...other attributes... />
                   <AndAnotherClass>
                        <FieldAAA tag="100" value="?" ...other attributes... />
                        <FieldBBB tag="200" value="?" ...other attributes... />
                        <FieldCCC tag="300" value="?" ...other attributes... />
                    <AndAnotherClass>
             </AnotherClass>

     <FieldB tag="000B" value="?"    ...other fields...>
             <AnotherClass>
                    <FieldX tag="100" value="?" />
                    <FieldY tag="200" value="?" />
                    <FieldZ tag="300" value="?" />
             </AnotherClass>
     <FieldC tag="000C" value="?"    ...other attributes... >
             <AnotherClass>
                    <FieldX tag="100" value="?" ...other attributes... />
                    <FieldY tag="200" value="?" ...other attributes... />
                    <FieldZ tag="300" value="?" />
             <AnotherClass>

   </Class1>
</Data>

So I need to put the client array into the XML filling in the "value" field where the "tag" fields match.

Perhaps this could be done automatically using some databinding?
if not how do I go through all XML children, get the "tag" field and fill in the "value" field.  I don't know how to iterate through all the XML to fill in the data as there are children-of-children-of children, not just a "simple" XML.

Thanks in advance for help with the code. Hopefully I have explained things right

Thanks
0
rwallacej
Asked:
rwallacej
  • 3
  • 2
1 Solution
 
Jens FiedererCommented:
You could use XPath constructs to select the nodes that apply, and modify them.  

If you need some help in that (after you look up the Xpath selection statements) I would be happy to guide you through it.
0
 
rwallacejAuthor Commented:
hi jensfiederer

thanks for comment, I came to the following code before your comment.
Not sure how efficient it is / how well if performs compared with XPath though, if XPath can do the same thing
comments welcome
thanks
    ''' <summary>
    ''' Search root element where there is a Tag attribute of value specified
    ''' </summary>
    ''' <param name="root"></param>
    ''' <param name="tagValue">value of tag to search for (unique)</param>
    ''' <param name="tagAttributeID">XML attribute name of Tag field</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function FindXElementRecursively(ByVal root As XElement, ByVal tagValue As String, ByVal tagAttributeID As String) As XElement
        Dim current As XElement = root
 
        If current.Attribute(tagAttributeID) = tagValue Then
            Return current
        End If
 
        Dim found As XElement
        For Each control As XElement In current.Descendants
            found = FindXElementRecursively(control, tagValue, tagAttributeID)
            If found IsNot Nothing Then
                Return found
            End If
        Next
 
        Return Nothing
    End Function
 
    ''' <summary>
    ''' Iterate through entire XML file, replace the "value" field with data where the "tag" field matches.
    ''' </summary>
    ''' <param name="filename">XML to load</param>
    ''' <param name="data">Collection of tag/values</param>
    ''' <param name="tag">XML attribute name of Tag field</param>
    ''' <remarks></remarks>
    Public Sub populateXMLwithKeyValueData(ByVal filename As String, ByVal data As System.Collections.Generic.List(Of ETData), ByVal tag As String)
        Try
            Dim reader = New XmlTextReader(filename)
            Dim readElement = XElement.Load(reader)
            Dim desc = readElement.Descendants
 
            For count As Integer = 0 To data.Count - 1
                Dim xe = FindXElementRecursively(desc.ElementAt(0), data(count).tag, tag)
                If xe IsNot Nothing Then
                    xe.Attribute("value").Value = data(count).value
                End If
            Next
        Catch ex As Exception
            Utils.LogException(ex)
        End Try
    End Sub
 
    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim data As New System.Collections.Generic.List(Of ETData)
        With data
            .Add(New ETData("30000", "123"))
            .Add(New ETData("100", "999"))
            .Add(New ETData("1001", "20000"))
            .Add(New ETData("2002", "12345"))
            .Add(New ETData("20000", "9171.0"))
            .Add(New ETData("......", "9171.0"))
        End With
 
        Call populateXMLwithKeyValueData(Server.MapPath("~/App_Data/XMLIterate.xml"), data, "tag")
    End Sub

Open in new window

0
 
Jens FiedererCommented:
I don't know how the efficiency compares (you can always benchmark it), but the XPath gives you a very READABLE approach - it handles the recursion for you.  The "Select Nodes" call does the grunt work.

            XmlDocument doc = new XmlDocument();
            doc.Load(filename);
            XmlNodeList nodes = doc.SelectNodes("//*[@value]");
            foreach (XmlNode node in nodes)
            {
               // abuse the node by adding your info HERE
            }
0
 
rwallacejAuthor Commented:
thank-you very much for your help

regards

rwallacej
0
 
Jens FiedererCommented:
My pleasure.

XPath lets you specify node sets nicely.  As MSDN puts it:
----------------------------------------------------
book[excerpt]
 All <book> elements that contain at least one <excerpt> element.
 
book[excerpt]/title
 All <title> elements inside <book> elements that contain at least one <excerpt> element.
 
book[excerpt]/author[degree]
 All <author> elements that contain at least one <degree> element, and are inside of <book> elements that contain at least one <excerpt> element.
 
book[author/degree]
 All <book> elements that contain at least one <author> element with at least one <degree> child element.
 
book[excerpt][title]
 All <book> elements that contain at least one <excerpt> element and at least one <title> element.
----------------------------------------------------

and you use "@" to indicate attribute in any of those.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now