python2.7开发实现xml顺序读取和写入,统一去空格功能

1.项目背景

           因为工作需要,xml文件夹下需要修改xml节点属性,统一定制poll_time属性结点,添加的xml结点目录为board\item\cpu\devs\dev\list\port\defaulttype下面添加属性attribute\poll_time 下interval =1000
手动添加太过于烦琐,尤其是有些单板存在很多端口的情况,考虑用python脚本添加。项目实例如下:

<?xml version="1.0" encoding="utf-8"?>
<board boardid ="2377" name="FOAD20"  service="boardctrl">
    <item phybomid="0xff" customid="0xff" pcb="0xff">
        <cpu type="_CPU_ARMQORIQLE" index="0" logicindex="0"  cpucardindex="0xff" cpucardtype="DEV_TYPE_BOARD_SELF" >
            <devs>
                <dev type="DEV_TYPE_PORT"  name="osc_voa_oba_opa_soms" >
                    <list  index="0" service="ethsubcard">
                        <attribute>
                            <firmware_version val="driver"/>
                        </attribute>
                        <port range="[1,1]" >
                             <defaulttype value="PORT_TYPE_OSC_SI" >
                                <interrupts>
                                    <interrupt event="289"  period="2" limit="50" enable="yes"/>
                                </interrupts>
                             </defaulttype>
                        </port>
                    </list>
                    <list  index="1" service="ethsubcard">
                        <port range="[1,1]" >
                             <defaulttype value="PORT_TYPE_OSC_SO" >
                                <interrupts>
                                    <interrupt event="289"  period="2" limit="50" enable="yes"/>
                                </interrupts>
                             </defaulttype>
                        </port>
                    </list> 
                    <list  index="2" service="ethsubcard">
                        <port range="[1,1]" >
                             <defaulttype value="PORT_TYPE_MONITOR_IN" >
                                <interrupts>
                                    <interrupt event="289"  period="2" limit="50" enable="yes"/>
                                </interrupts>
                             </defaulttype>
                        </port>
                    </list> 
                    <list  index="3" service="ethsubcard">
                        <port range="[1,1]" >
                             <defaulttype value="PORT_TYPE_VOA_MODULE" >
                                <interrupts>
                                    <interrupt event="289"  period="2" limit="50" enable="yes"/>
                                </interrupts>
                             </defaulttype>
                        </port>
                    </list> 
                    <list  index="4" service="ethsubcard">
                        <port range="[1,1]" >
                             <defaulttype value="PORT_TYPE_OTS_TTP_SI" >
                                <interrupts>
                                    <interrupt event="289"  period="2" limit="50" enable="yes"/>
                                </interrupts>
                             </defaulttype>
                        </port>
                    </list>

2.开发过程中遇到的困难

1.python解析的xml结点读出来后,每一个xml节点按照字典序排序,极大的改变了xml的节点结构,不利于代码走查和代码管理
2.python开发过程中发现xml结点的编码方式  <?xml version="1.0" encoding="utf-8" ?> 为双引号而并非单引号
3.使用python脚本最大的误区是使用了python3.7版本导致版本不对,前面的xml按照顺序写入编译找不到相关的库,而因为不熟悉,想了各种方式没有解决

解决方法:
基于python2.7重写python的element.py源码,如下所示:
# =======================================================================
# 重写python源码,禁止读取xml后顺序写入
# =======================================================================
def _serialize_xml(write, elem, encoding, qnames, namespaces):
    tag = elem.tag
    text = elem.text
    if tag is ET.Comment:
        write("<!--%s-->" % ET._encode(text, encoding))
    elif tag is ET.ProcessingInstruction:
        write("<?%s?>" % ET._encode(text, encoding))
    else:
        tag = qnames[tag]
        if tag is None:
            if text:
                write(ET._escape_cdata(text, encoding))
            for e in elem:
                _serialize_xml(write, e, encoding, qnames, None)
        else:
            write("<" + tag)
            items = elem.items()
            if items or namespaces:
                if namespaces:
                    for v, k in sorted(namespaces.items(),
                            key=lambda x: x[1]):  # sort on prefix
                        if k:
                            k = ":" + k
                        write(" xmlns%s=\"%s\"" % (
                            k.encode(encoding),
                            ET._escape_attrib(v, encoding)
                        ))
                # for k, v in sorted(items):  # lexical order
                for k, v in items:  # Monkey patch
                    if isinstance(k, ET.QName):
                        k = k.text
                    if isinstance(v, ET.QName):
                        v = qnames[v.text]
                    else:
                        v = ET._escape_attrib(v, encoding)
                    write(" %s=\"%s\"" % (qnames[k], v))
            if text or len(elem):
                write(">")
                if text:
                    write(ET._escape_cdata(text, encoding))
                for e in elem:
                    _serialize_xml(write, e, encoding, qnames, None)
                write("</" + tag + ">")
            else:
                write("/>")
    if elem.tail:
        write(ET._escape_cdata(elem.tail, encoding))
ET._serialize_xml = _serialize_xml


def _serialize_text(write, elem, encoding):
    for part in elem.itertext():
        write(part.encode(encoding))
    if elem.tail:
        write(elem.tail.encode(encoding))
ET._serialize_text = _serialize_text

_serialize = {
    "xml": _serialize_xml,
    "html": ET._serialize_html,
    "text": _serialize_text,
# this optional method is imported at the end of the module
#   "c14n": _serialize_c14n,
}
ET._serialize = _serialize



def write(self, file_or_filename,
          # keyword arguments
          encoding=None,
          xml_declaration=None,
          default_namespace=None,
          method=None):
    # assert self._root is not None
    if not method:
        method = "xml"
    elif method not in _serialize:
        # FIXME: raise an ImportError for c14n if ElementC14N is missing?
        raise ValueError("unknown method %r" % method)
    if hasattr(file_or_filename, "write"):
        file = file_or_filename
    else:
        file = open(file_or_filename, "wb")
        # file = codecs.open(file_or_filename,"w","utf-8-sig")
    write = file.write
    if not encoding:
        if method == "c14n":
            encoding = "utf-8"
        else:
            encoding = "us-ascii"
    elif xml_declaration or (xml_declaration is None and
                                     encoding not in ("utf-8", "us-ascii")):
        if method == "xml":
            write('<?xml version="1.0" encoding="%s"?>\r\n' % encoding)
    if method == "text":
        _serialize_text(write, self._root, encoding)
    else:
        qnames, namespaces = ET._namespaces(
            self._root, encoding, default_namespace
        )
        serialize = _serialize[method]
        serialize(write, self._root, encoding, qnames, namespaces)
    if file_or_filename is not file:
        file.close()
ET.ElementTree.write = write


class OrderedXMLTreeBuilder(ET.XMLTreeBuilder):
    def _start_list(self, tag, attrib_in):
        fixname = self._fixname
        tag = fixname(tag)
        attrib = OrderedDict()
        if attrib_in:
            for i in range(0, len(attrib_in), 2):
                attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i + 1])
        return self._target.start(tag, attrib)
# =======================================================================
# 重写python源码,禁止读取xml后顺序写入
# =======================================================================

4.在修改xml过程中,发现写入的xml节点不能可视化显示,可读性能差,只有用浏览器打开正常显示,显然这样不符合我们的要求,需要新增函数:

def indent(elem, level=0):
    i = "\n" + level*"\t"
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "\t"
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
        for elem in elem:
            indent(elem, level+1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i

5.在修改xml文件的时候,有的文件因为table转了空格,有的文件因为没有转空格,而代码走查过程中需要xml文件实现table转空格需求,否则会出现大量修改不对称和修改后大面积table显示问题

#table转空格
def tableSpace(file_name,lis_out,tab_num = 4):
    file_str = open(file_name,"r").read()
    if "\t" in file_str:
        lis_out.append(file_name)
        open(file_name,"w").write(file_str.expandtabs(tab_num))

6.python新增节点存在需求不明确的地方:

  (1)attribute节点存在的情况,直接添加poll_time
  (2)attribute节点不存在的情况,需要先添加attribute再添加

# 遍历所有的defaulttype标签
for defaulttype in root.findall("item/cpu/devs/dev/list/port/defaulttype"):
	attribute = defaulttype.find("attribute")
	if attribute is None:
		attribute  = ET.SubElement(defaulttype,"attribute")
		subElement(attribute, "poll_time", "interval","1000")
	else:
		poll_time = attribute.find("poll_time")
		if poll_time is None:#判断一下是不是空的,没有这个属性结点才写
			subElement(attribute, "poll_time", "interval","1000")

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值