Help with replacing values in xml files

Posted on 2012-09-19
Medium Priority
Last Modified: 2012-10-16
I have two xml files (ItemA.xml, ItemB.xml) linked to another xml file (Link.xml) as shown below.


<ItemA> ItemA1</ItemA>
<ItemA> ItemA2</ItemA>


<ItemB> ItemB1</ItemB>
<ItemB> ItemB2</ItemB>


<ItemA_ID> 1</ItemA_ID>
<ItemB_ID> 1</ItemB_ID>
<ItemA_ID> 2</ItemA_ID>
<ItemB_ID> 2</ItemB_ID>

I need to compare the two other xml files (ItemC.xml, ItemD.xml) with the first two mentioned above (ItemA.xml, ItemB.xml)and copy data from ItemC and ItemD to ItemA and ItemB if they don't already exist in ItemA and ItemA.

How I achieve this?

An How do I update the Link.xml with the latest ID of ItemC and ItemD created when adding data to ItemA and ItemB?


Question by:vcharles
  • 4
  • 4

Expert Comment

ID: 38413681
I'm curious as to what you are trying to accomplish. It looks like a relational database would be better utilized to manage that data rather than 5 different xml files.

I've never compared multiple xml files, but I have read data into a dictionary variable, then used the Contains method to see if a key/value pair exists.

Adding data to an xml file is relatively easy, once you know what tags you need and where in the hierarchy to put the new lines. There are a lot of good tutorials and instructional forums on the 'net.
LVL 60

Expert Comment

by:Geert Bormans
ID: 38413717
Well, I would do such effort using XSLT
If you would be bound to XSLT1 (if for example you are in a .net environment)
you would need three transforms, one for each file you are transforming
If you would use an XSLT2 transformer such as saxon (in a java environment or command line)
you could get this done in one go

It is a straightforward task using keys in XSLT and recommended over a RDBMS approach for smaller files. For big files I would go to a repository solution in order to index the lookups.

Could be done in code (python, ruby, .... whatever too) I would still prefer an XSLT transform, would be easier to handle. Note, three transforms still could mean one XSLT program

Author Comment

ID: 38414168

I have to use xml with VB.NET for this project, any links addressing this type of issue would be very helpful. Thanks for your comments.

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.


Author Comment

ID: 38440455

Expert Comment

ID: 38440672
One idea: read each XML into a dictionary object, then loop through one dictionary and use the Contains method against another dictionary. Whatever isn't in both dictionaries gets added to another object (I'd probably create a class collection to track the tag and value, or use a dictionary object specifically for that). Once all the outstanding values are gathered, I'd add the outstanding values to the target xmls utilizing either XElement objects or XMLDocument-type objects, whichever works better in your situation.

Author Comment

ID: 38440710
I am totally lost, can you please end me an example or links on how to use dictionaries?

Expert Comment

ID: 38440967
Here's some sample code I use in one of my programs to read XML, load dictionary objects, load a custom class, and change values in an XML branch:

    Private Sub PullXMLData()
        Dim xdoc As New XmlDocument
        xdoc.Load(sXMLPath & "lasermark.xml")
        'select node that matches parent item
        'Dim xmlNodes As XmlNodeList = xdoc.GetElementsByTagName("pn")
        'For Each node As XmlNode In xmlNodes
        '    If node.Attributes("pn").Value = MasterData.Parent_Item Then
        '        'this is the node we want
        '        sNeoorSJM = node.Attributes("neoorsjm").Value

        '    End If 'node.Attributes("pn").Value = MasterData.Parent_Item Then
        'Next 'node as XmlNOde in xmlNodes
        'let's try selective node parsing
        Dim xNodeList As XmlNodeList
        Dim xChildren As XmlNodeList
        Dim xNode As XmlNode
        Dim nod As XmlNode

        Dim iCount As Integer = 0
        Dim x As Integer = 0
        Dim y As Integer = 0
        Dim z As Integer = 0

        Dim dChildAtts() As Dictionary(Of String, String)
        Dim dChildnodesVals() As Dictionary(Of String, String)
        Dim bHasChildren As Boolean = False
        'already loaded xDoc
        xNodeList = xdoc.SelectNodes("/parts/partnumber[@pn='" & MasterData.Parent_Item & "']")
        ReDim dChildAtts(xNodeList.Count - 1)
        For Each xNode In xNodeList
            'pull the attributes of all the nodes
            dChildAtts(x) = New Dictionary(Of String, String)
            Dim childAttsCt = xNode.Attributes.Count
            If childAttsCt > 0 Then
                For y = 0 To childAttsCt - 1
                    With dChildAtts(x)
                        .Add(xNode.Attributes.Item(y).Name.ToString, xNode.Attributes.Item(y).Value.ToString)
                    End With
                Next 'y = 0 to childAttsCt - 1
            End If 'childAttsCt > 0 then
            x += 1
        Next 'xNode in xNodeList
        'now dChildAtts should hold the attributes of the partnumber nodes

        xNode = xdoc.SelectSingleNode("/parts/partnumber[@pn='" & MasterData.Parent_Item & "']/serialnumber")
        iCount = xNode.ParentNode.ChildNodes.Count
        'icount is now the total number of nodes under th parent (partnumber node)
        ReDim dChildnodesVals(iCount - 1) 'size teh array to handle all the nodes, then add the children of those nodes
        'to the dictionary
        Do While xNode IsNot Nothing
            dChildnodesVals(z) = New Dictionary(Of String, String)
            If xNode.Attributes.Count > 0 Then
                For x = 0 To (xNode.Attributes.Count - 1)
                    dChildnodesVals(z).Add(xNode.Attributes.Item(x).Name.ToString, xNode.Attributes.Item(x).Value.ToString)
                Next 'x = 0 to (xnode.attributes.count - 1)
                xChildren = xNode.ChildNodes
                For Each nod In xChildren
                    dChildnodesVals(z).Add(nod.Name.ToString, nod.InnerText.ToString)
                Next 'nod in xChildren
                dChildnodesVals(z).Add(xNode.Name.ToString, xNode.InnerText.ToString)
            End If 'xnode.attributes.count > 0 
            z += 1
            xNode = xNode.NextSibling
        Loop 'xnode isnot nothing

        'now we have a dictionary array that holds the attributes of every partnumber node (dChildAtts)
        'and a dictionary array holding a member for each child node under a particular partnumber node (dchildnodesvals)
        For y = 0 To UBound(dChildAtts)
            For Each kvp As KeyValuePair(Of String, String) In dChildAtts(y)
                Debug.Print("dChildAtts(" & y & "): " & kvp.Key & " " & kvp.Value)
            Next 'kvp in dChildAtts
        Next ' y = 0 To UBound(dChildAtts)

        For y = 0 To UBound(dChildnodesVals)
            For Each kvp As KeyValuePair(Of String, String) In dChildnodesVals(y)
                Debug.Print("dchildnodesVals(" & y & "): " & kvp.Key & " " & kvp.Value)
                Select Case LCase(kvp.Key)
                    Case "issserialized"
                        MasterData.IsSerialized = kvp.Value
                    Case "lastsnused"
                        MasterData.LastSNUsed = kvp.Value
                    Case "snprefix"
                        MasterData.SNPrefix = kvp.Value
                    Case "idnumber"
                        MasterData.IDNumber = kvp.Value
                    Case "lastcasecode"
                        MasterData.CaseCode = kvp.Value
                    Case "lastpalletcode"
                        MasterData.PalletCode = kvp.Value
                    Case "ubd"
                        MasterData.UBDLength = kvp.Value
                    Case "ubdformat"
                        MasterData.UBDFormat = kvp.Value
                    Case "datecodeformat"
                        MasterData.Date_Format = kvp.Value
                    Case "laserfilepath"
                        MasterData.Laser_File_Path = kvp.Value
                    Case "customerpn"
                        MasterData.Cust_PN = kvp.Value
                    Case "haslabels"
                        MasterData.HasLabels = kvp.Value
                    Case "usetemplate"
                        MasterData.Use_Template = kvp.Value
                    Case "templatename"
                        MasterData.Template_Name = kvp.Value
                    Case "labelfilepath"
                        MasterData.LabelFilePath = kvp.Value
                    Case "staticbarcodedata"
                        MasterData.StaticBarcodeData = kvp.Value
                    Case "bagstock"
                        MasterData.BagStock = kvp.Value
                    Case "boxstock"
                        MasterData.BoxStock = kvp.Value
                    Case "casestock"
                        MasterData.CaseStock = kvp.Value
                    Case "boxqty"
                        MasterData.Box_Qty = kvp.Value
                    Case "caseqty"
                        MasterData.Case_Qty = kvp.Value
                    Case "csvfilepath"
                        MasterData.CSVFilePath = kvp.Value
                    Case "fixturenumber"
                        MasterData.FixtureNumber = kvp.Value
                    Case "onetwolr"
                        If LCase(kvp.Value) = "onetwo" Then
                            MasterData.OneTwo = True
                        ElseIf LCase(kvp.Value) = "leftright" Then
                            MasterData.Left_Right = True
                        End If 'lcase(kvp.value) = "onetwo"
                End Select
        Next 'y = 0 To UBound(dChildnodesVals)
    End Sub
    Private Sub UpdateXML(ByVal sWhichValue As String, ByVal sNewValue As String)
        Dim xDoc As New XmlDocument
        Dim xNode As XmlNode

        xDoc.Load(sXMLPath & "lasermark.xml")
        Select Case sWhichValue
            Case "sn"
                xNode = xDoc.SelectSingleNode("/parts/partnumber/[@pn='" & MasterData.Parent_Item & "']/serialnumber/lastsnused")
            Case "caseid"
                xNode = xDoc.SelectSingleNode("/parts/partnumber/[@pn='" & MasterData.Parent_Item & "']/serialnumber/lastcasecode")
            Case "palletid"
                xNode = xDoc.SelectSingleNode("/parts/partnumber/[@pn='" & MasterData.Parent_Item & "']/serialnumber/lastpalletcode")
        End Select
        xNode.InnerText = sNewValue
        xDoc.Save(sXMLPath & "lasermark.xml")
        xNode = Nothing
        xDoc = Nothing
    End Sub

Open in new window


Author Comment

ID: 38440994
Thanks, will get back to you.

Accepted Solution

JulieHolmes earned 2000 total points
ID: 38441052
Here's a short bit about checking existing keys/values in dictionary. This is from VB6, so the Exists method then is replaced by the Contains method now:
Public PalletLog As New Dictionary 'for storing casecodes on the pallet

                    'stextin should be casecode
                    'so, check case data to see if case has been assigned to a pallet yet.
                    'first, is this case in the casetracker collection already?
                    'can't do exists; need to pull csv and check .shippingunitid
                    'If CaseTracker.Exists(sTextIn) Then
                    If PalletLog.Exists(sTextIn) Then
                        'already exists in pallet
                        MsgBox "Duplicate Scan. Please try again.", vbInformation, "Already Scanned"
                        Exit Function
                    Else  'look up case csv and add to casetracker
                        'add casecode to palletlog
                        PalletLog.Add sTextIn, Format(Now(), "yyyy-mm-dd_HhMmSS")

                    End If 'CaseTracker.Exists(sTextIn) Then

Open in new window

this code is used to check to see if a case has already been scanned and pegged to a pallet. Each case has a unique number, so if the pallet dictionary already has that case ID in it, an error will be thrown. This is older code that used CSV files rather than XML files to track the list. The CSV file is read into a dictionary in the beginning of the program, so any cases already pegged to the pallet are in the PalletLog dictionary (that code isn't here). Hopefully this gives an idea of how this can be done. I'm sure there's a lot of more advanced programmers out there than me, who have better methods. This is just one way to approach it.

Featured Post

Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Screencast - Getting to Know the Pipeline
Suggested Courses

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question