我试图通过克隆各种节点(和节点组)来使用 Python 从 XML 文件中读取数据结构,然后更改节点中的一些数据并将其粘贴到新的 .xml 文件中。
我目前有这个代码 - 它包含在一个 for 循环中,因为我试图从一个克隆节点创建多个节点。每个新节点与克隆的数据略有不同:
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
我遇到的问题是,虽然在最后附加节点之前数据似乎设置得很好(由打印语句检查),但当我实际检查输出文件时,它实际上只是获取了“更深”的数据'.cloneNode(True)' 节点并直接复制它而不做任何更改,这对我来说绝对没有意义。我使用了错误的数据更改功能还是什么?
编辑:请找到完整的代码:
#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)