1

I'm trying to read in the data structures from an XML file using Python by cloning various nodes (and groups of nodes), then changing some of the data within the nodes and pasting it out to a new .xml file.

I currently have this code - it is enclosed in a for loop as I am trying to create multiple nodes from one cloned node. Each new node has slightly different data from the clone:

i = 1

for alias in newchannels[:]:

    #split'alias' at commas and assign to content - this bit is just to retrieve the    correct data to be pasted into the nodes later
    content = alias.split(',')
    #extract data from array
    channelname = content[0]
    #ditto
    ip = content[2]
    port = content[3]

    #get channel info
    root_sChannel = root_sChannelList.getElementsByTagName("servermain:Channel")[0]
    #blank channel node
    root_sChannelClone = root_sChannel.cloneNode(False)

    #root_sChannelClone.firstChild.data = "SimulationChannel " + str(i)

    #clone servermain:Name attribute from previous xml file

    servermainName = root_sChannel.getElementsByTagName("servermain:Name")[0]

    #clone it
    servermainNameClone = servermainName.cloneNode(True)

    servermainNameClone.data = "SimulationChannel" + str(i)
    #this bit prints the data fine 
    print servermainNameClone.data
    #servermainNameClone.setAttributeNode("Simulation Channel" + str(i)) 

    #append to channel clone
    root_sChannelClone.appendChild(servermainNameClone)
    #this bit still prints the data fine
    print servermainNameClone.data

    #append other data here

    root_sChannelListClone.appendChild(root_sChannelClone)

    i+=1

The problem that I am having is that although the data seems to be setting fine before appending the nodes at the end (as checked by the print statements), when I actually check the outputted file, it has actually just taken the 'deeper' data of the '.cloneNode(True)' node and copied it straight over with no change, which makes absolutely no sense to me. Am I using the wrong data changing function or something?

Edit: Please find attached the full code:

    #include necessary modules
import xml.dom.minidom
import csv
import os
import argparse
import sys

#set defaults
WELLS_FILE = "wells.csv"
CONFIG_FILE = "OPCServerConfig.xml"
UPDATE_FILE = "UpdatedConfig.xml"

#set constants for the column locations in CSV file
_Tenement=0
_Well=1
_Type=2
_Descr=3
_RealIP=4
_TestIP=5
_TestPort=6

#set port
_PORT="5020"

global FILES

def parseInput():
    #set up argument parser
    parser = argparse.ArgumentParser(description='Update Kepware Server Configuration with wells information.')
    #add arguments (parameters) to the parser - the info needed when running the program
    parser.add_argument('-wf','--wells', default=WELLS_FILE, help='wells file' )
    parser.add_argument('-cf','--config', default=CONFIG_FILE, help='current configuration file')
    parser.add_argument('-of','--output', default=UPDATE_FILE, help='updated configuration file')

    global FILES
    #above info stored until this line when they are actually used - then creates the necessary objects. sys.arg[1] reads argument 2 onwards from command line
    FILES = parser.parse_args(sys.argv[1:])

    #print out files names
    print FILES.wells
    print FILES.config
    print FILES.output

#reads in well info
def getWellsInfo():
    #set up empty array
    lines = []
    #set header to true by default (i.e. it hasn't found the header yet)
    header = True
    #open the wells.csv file, to be read in binary mode ('rb')
    with open( FILES.wells, 'rb') as wellfile:
            #assign tothe variable reader the wellfile
            reader = csv.reader(wellfile)
            #for each row in the csv file
            for row in reader:
                #if row is empty, or starts with '//' then go to next loop of for statement
                if len(row)==0 or row[0].startswith("//") or not row[0]:
                    continue

                #if header found, set value to false, then go to next loop
                if header:
                    header = False
                    continue

                #assign info from csv file to applicable arrays
                #t_nm = row[ _Tenement ]
                #w_nm = row[ _Well ]
                #real_ip_nm = row[ _RealIP ]
                test_ip_nm = row[ _TestIP ]

                #set up construct for channel name
                #channel = "B%(tnm)03d-w%(wnm)03d" % {'tnm':int(t_nm), 'wnm':int(w_nm) }
                channel = row[ _Descr ]
                # alias = "ARG_WH%(wnm)02d" % {'wnm':int(w_nm) }
                #alias = "B%(tnm)03d-w%(wnm)03d" % {'tnm':int(t_nm), 'wnm':int(w_nm) }
                alias = row[ _Descr ]

                port = row[ _TestPort ]

                #print out info to command prompt
                print channel + ',' + alias + ',' + test_ip_nm.split('/')[0] + ',' + port
                #append info contructs to lines array
                lines.append(channel + ',' + alias + ',' + test_ip_nm.split('/')[0] + ',' + port)

    wellfile.close()
    return lines

def updateCfgFile(newchannels):
    from xml.dom.minidom import parse
    #parse the xml file and assign it to 'doc'
    doc = parse(FILES.config)
    #get the first 'Matrikon.OPC.ScadaModbus' element by tag name and assign it to root
    root = doc.getElementsByTagName("servermain:Project")[0]
    #clone (copy) the node, but not a 'deep' (children) copy, as specified by the 'false' parameter
    rootClone = root.cloneNode(False)

    #get the title element and assign it to the variable root_sTitleClone
    root_sTitle = root.getElementsByTagName("servermain:Title")[0]
    #clone the node but not a deep clone
    root_sTitleClone = root_sTitle.cloneNode(False)

    #as above for comments
    root_sComments = root.getElementsByTagName("servermain:Comments")[0]
    root_sCommentsClone = root_sComments.cloneNode(False)

    #as above for AliasList
    root_sAliasList = root.getElementsByTagName("servermain:AliasList")[0]
    root_sAliasListClone = root_sAliasList.cloneNode(False)

    #as above for GlobalDriverSettingsList, copy all child stuff too (cloneNode:True)
    root_sGDSL = root.getElementsByTagName("servermain:GlobalDriverSettingsList")[0]
    root_sGDSLClone = root_sGDSL.cloneNode(True)


    #append the children to the rootClone hierarchy
    rootClone.appendChild( root_sTitleClone )
    rootClone.appendChild( root_sCommentsClone )
    rootClone.appendChild( root_sAliasListClone )
    rootClone.appendChild( root_sGDSLClone )

    #as above for ChannelList
    root_sChannelList = root.getElementsByTagName("servermain:ChannelList")[0]
    root_sChannelListClone = root_sChannelList.cloneNode(False)







    #for loop interation
    i=1
    #create array 'newchannels' and cycle through it using indexes 'alias'
    for alias in newchannels[:]:
        #split'alias' at commas and assign to content
        content = alias.split(',')
        #extract data from array
        channelname = content[0]
        #ditto
        ip = content[2]
        port = content[3]

        #get channel info
        root_sChannel = root_sChannelList.getElementsByTagName("servermain:Channel")[0]
        #blank channel node
        root_sChannelClone = root_sChannel.cloneNode(False)

        #root_sChannelClone.firstChild.data = "SimulationChannel " + str(i)

        #clone servermain:Name attribute from previous xml file
        servermainName = root_sChannel.getElementsByTagName("servermain:Name")[0]
        #clone it
        servermainNameClone = servermainName.cloneNode(True)

        servermainNameClone.data = "SimulationChannel" + str(i) 
        print servermainNameClone.data
        #servermainNameClone.setAttributeNode("Simulation Channel" + str(i)) 

        #append to channel clone
        root_sChannelClone.appendChild(servermainNameClone)
        print servermainNameClone.data

        #append other data here

        root_sChannelListClone.appendChild(root_sChannelClone)

        i+=1


        #sDriver = root_sChannel.getElementsByTagName("servermain:Driver")
        #root_sChannelClone.appendChild(sDriver)




        #set name of channel clone
        #root_sChannelClone_ServerName.setAttribute("servermain:Name", "Simulation Channel " + str(i))

        #root_sChannelCloneDeviceList = root_sChannel.getElementsByTagName("servermain:DeviceList")

        #root_sChannelCloneDevice = root_sChannelCloneDeviceList.getElementsByTagName("servermain:Device")[0]

        #root_sChannelCloneDevice.setAttribute("servermain:Name", channelname)
        #root_sChannelCloneDeviceList.setAttribute("servermain:Name", "value inserted here")

        #root_sChannelCloneDevice.setAttribute("servermain:ID", ip)
        #root_sChannelCloneDeviceList.setAttribute("servermain:ID", "IP Inserted here")

        #root_sChannelCloneDevice.setAttribute("Modbus_ethernet:Port", port)
        #root_sChannelCloneDeviceList.setAttribute("Modbus_ethernet:Port", "portnumber here")

        #root_sChannelListClone.appendChild ( root_sChannelClone )


    rootClone.appendChild( root_sChannelListClone )

    #rootClone.appendChild( root_sChannelListClone )
    '''    
    #print out channel name, ip and port
    for channel in rootDevLinkClone.getElementsByTagName("CNetworkChannelDevLink"):
        name = channel.getAttribute("name")
        devlink = channel.getElementsByTagName("CHostDevLink")[0]
        ip = devlink.getAttribute("host")
        port = devlink.getAttribute("service")
        print name + ' ' + ip + ' ' + port
    '''
    #PSTAliasGroup = rootAlias.getElementsByTagName("PSTAliasGroup")[0]

    #for alias in newchannels[:]:
    #    channelname = alias.split(',')[0]
    #    aliasname = alias.split(',')[1]
    #    GroupClone = PSTAliasGroup.cloneNode(True)
    #    GroupClone.setAttribute("name",aliasname)
    #    Taglist = GroupClone.getElementsByTagName("PSTAlias")
    #    for tag in Taglist[:]:
    #        pathlist = tag.getAttribute("itemPath").split('.')
    #        newpath = channelname
    #        for pathfrag in pathlist[1:]:
    #            newpath += '.' + pathfrag
    #        tag.setAttribute("itemPath", newpath)
    #    rootAliasClone.appendChild(GroupClone)

    print "Saving..."

    ## This makes a second, larger copy of the XML data !!
    # xmlString = rootClone.toprettyxml()

    #output the file
    outputfile = open(FILES.output, 'w')
    #outputfile.write(xmlString)

    #write xml of the root clone hierarchy
    rootClone.toprettyxml(indent='  ')
    rootClone.writexml(outputfile, "    ", "    ", "\n");
    outputfile.close()
#print xmlString

#call the parse input function - sets up user argument validating etc       
parseInput()

print FILES

#call the get wells info function - retrieves all necessary info from the wells.csv file
ips = getWellsInfo()

print ips

#call update cfg file
updateCfgFile(ips)
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • 2
    plase provide the whole code because we dont know which type of variable and lib you are using like `root_sChannelList` is xmldom but others we dont know. – Nilesh Feb 21 '12 at 12:44

0 Answers0