Help with replacing values in xml files

Posted on 2012-09-19
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
    LVL 1

    Expert Comment

    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
    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


    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.


    Author Comment

    LVL 1

    Expert Comment

    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

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

    Expert Comment

    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

    Thanks, will get back to you.
    LVL 1

    Accepted Solution

    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.

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    6 Surprising Benefits of Threat Intelligence

    All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

    Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
    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…
    Hi everyone! This is Experts Exchange customer support.  This quick video will show you how to change your primary email address.  If you have any questions, then please Write a Comment below!
    Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

    737 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

    Need Help in Real-Time?

    Connect with top rated Experts

    22 Experts available now in Live!

    Get 1:1 Help Now