在使用python中的xml.etree.ElementTree库解析xml文件时,默认不会做任何的换行和缩进处理,导致输出的xml文件阅读起来很不方便。以高通平台小基站射频校准配置文件为例,笔者希望该xml文件的格式如下所示,这样很容易找出Tx、Rx、Nl等等射频链路的校准配置。

<?xml version='1.0' encoding='utf-8'?>
<CalConfigDefinitions>
	<BoardConfigs>
		<BoardDef name="F02001-2" configs="F02001-2_LTE20" />
	</BoardConfigs>
	<CalConfigs>
		<CalConfig name="F02001-2_LTE5" topology="407">
			<TxConfig txPathIdList="TX1,TX2" antennaNum="1,2" bwConst="LTE5" band="B41" fg="2" enableFb="false" txRefFreq="2590" listOfTxSweepFreqMhz="2498.5,2510.5,2520.5,2530.5,2540.5,2560.5,2580.5,2600.5,2620.5,2640.5,2660.5,2670.5,2680.5,2687.5" firstGainState="40" firstGainStatePowerLimitHigh="10" firstGainStatePowerLimitLow="-45" highestAllowedGainState="0" targetMaxPower="17" txDcLeakageLimit="-40" txIqImageLimit="-40" maxFreqSweepPeakToPeakDelta="10" rxFbDcLeakageLimitDbfs="-34" rxFbIqImageLimitDbc="-40" rxfbSignalDbfsMin="-20" rxfbSignalDbfsMax="0" txFreqSweepTargetReferencePowerDbm="17" txDigitalGainMaxDb="-3" txHighDcLeakageLimit="-43" txLowCutoffGainState="30" calDataAlsoAppliesTo="LTE10,LTE15,LTE20" txMonotonicCheckThresholdDb="-3" />
			<RxFb1AclrNoiseCal rxfbPathIdList="FB1,FB2" bwConst="LTE5" band="B41" fg="2" freq="2590" rxfbMaxGainState="16" />
			<RxConfig rxPathIdList="RX1,RX2" antennaNum="1,2" bwConst="LTE5" band="B41" fg="2" rxRefFreqMhz="2590" listOfRxSweepFreqMhz="2498.5,2510.5,2520.5,2530.5,2540.5,2560.5,2580.5,2600.5,2620.5,2640.5,2660.5,2670.5,2680.5,2687.5" rxGainStateList="0,1,2,3,4,5,6,7" rxSigGenPowersForGainState="-66,-59,-56,-51,-46,-41,-31,-21" rxDcLeakageLimitDbfs="-40" rxIqImageLimitDbc="-40" maxFreqSweepPeakToPeakDelta="10" rxSignalDbfsMin="-40" rxSignalDbfsMax="-20" calDataAlsoAppliesTo="LTE10,LTE15,LTE20" />
			<RxConfig rxPathIdList="NL1" antennaNum="3" bwConst="LTE20" band="B25" fg="3" rxRefFreqMhz="1960" listOfRxSweepFreqMhz="1930,1940,1945,1950,1955,1960,1965,1970,1975,1980,1985,1990,1995" rxGainStateList="0,1,2,3,4,5" rxSigGenPowersForGainState="-65,-57,-51,-40,-29,-18" rxDcLeakageLimitDbfs="-40" rxIqImageLimitDbc="-40" maxFreqSweepPeakToPeakDelta="10" rxSignalDbfsMin="-40" rxSignalDbfsMax="-20" />
		</CalConfig>
	</CalConfigs>
</CalConfigDefinitions>

而实际Python xml.etree.ElementTree库默认输出的xml文件如下,所有节点堆积在同一行。下面通过增加换行和缩进来美化xml文件,读者不需要纠结该xml文件的实际意义,本文仅以此为例。

<?xml version='1.0' encoding='utf-8'?>
<CalConfigDefinitions><BoardConfigs><BoardDef name="F02001-2" configs="F02001-2_LTE20" /></BoardConfigs><CalConfigs><CalConfig name="F02001-2_LTE5" topology="407"><TxConfig txPathIdList="TX1,TX2" antennaNum="1,2" bwConst="LTE5" band="B41" fg="2" enableFb="false" txRefFreq="2590" listOfTxSweepFreqMhz="2498.5,2510.5,2520.5,2530.5,2540.5,2560.5,2580.5,2600.5,2620.5,2640.5,2660.5,2670.5,2680.5,2687.5" firstGainState="40" firstGainStatePowerLimitHigh="10" firstGainStatePowerLimitLow="-45" highestAllowedGainState="0" targetMaxPower="17" txDcLeakageLimit="-40" txIqImageLimit="-40" maxFreqSweepPeakToPeakDelta="10" rxFbDcLeakageLimitDbfs="-34" rxFbIqImageLimitDbc="-40" rxfbSignalDbfsMin="-20" rxfbSignalDbfsMax="0" txFreqSweepTargetReferencePowerDbm="17" txDigitalGainMaxDb="-3" txHighDcLeakageLimit="-43" txLowCutoffGainState="30" calDataAlsoAppliesTo="LTE10,LTE15,LTE20" txMonotonicCheckThresholdDb="-3" /><RxFb1AclrNoiseCal rxfbPathIdList="FB1,FB2" bwConst="LTE5" band="B41" fg="2" freq="2590" rxfbMaxGainState="16" /><RxConfig rxPathIdList="RX1,RX2" antennaNum="1,2" bwConst="LTE5" band="B41" fg="2" rxRefFreqMhz="2590" listOfRxSweepFreqMhz="2498.5,2510.5,2520.5,2530.5,2540.5,2560.5,2580.5,2600.5,2620.5,2640.5,2660.5,2670.5,2680.5,2687.5" rxGainStateList="0,1,2,3,4,5,6,7" rxSigGenPowersForGainState="-66,-59,-56,-51,-46,-41,-31,-21" rxDcLeakageLimitDbfs="-40" rxIqImageLimitDbc="-40" maxFreqSweepPeakToPeakDelta="10" rxSignalDbfsMin="-40" rxSignalDbfsMax="-20" calDataAlsoAppliesTo="LTE10,LTE15,LTE20" /><RxConfig rxPathIdList="NL1" antennaNum="3" bwConst="LTE20" band="B25" fg="3" rxRefFreqMhz="1960" listOfRxSweepFreqMhz="1930,1940,1945,1950,1955,1960,1965,1970,1975,1980,1985,1990,1995" rxGainStateList="0,1,2,3,4,5" rxSigGenPowersForGainState="-65,-57,-51,-40,-29,-18" rxDcLeakageLimitDbfs="-40" rxIqImageLimitDbc="-40" maxFreqSweepPeakToPeakDelta="10" rxSignalDbfsMin="-40" rxSignalDbfsMax="-20" /></CalConfig></CalConfigs></CalConfigDefinitions>

软件环境说明

Python版本: Python 3.7
Xml解析库: xml.etree.ElementTree
IDE: PyCharm

网络上xml美化方法

遇到问题首先想到的是搜一下大神们是如何操作的,网上的解决办法基本上大同小异:在创建好所有节点之后、初始化tree之前进行换行(\n)和缩进(\t)处理,如以下部分代码所示。

def prettyXml(self,tree,indent,newline,level=0):
    Pretty Xml File before writing
    :param tree: 创建好的父节点,未初始化的tree
    :param indent: 缩进“\t”
    :param newline: 换行“\n”
    :param level: 用于递归操作的变量,实现不同级别节点增加不同数量的缩进“\t”
    :return: 无
    treeList=list(tree)
    for subElement in treeList:
        # print(subElement)
        if treeList.index(subElement) < (len(treeList) - 1):
            subElement.tail=newline+indent*(level+1)
        else:
            subElement.tail=newline+indent*level
        self.prettyXml(subElement,indent,newline,level+1)
# parent_node的创建过程省略
prettyXml(parent_node,'\t','\n')		# 换行和缩进处理
tree=ET.ElementTree(parent_node)		# 初始化tree,ET为导入的xml.etree.ElementTree,导入过程省略
write_xml(tree, r"E:\2_PersonalStudy\1_PythonStudy\MyPyCharmProject\TestDemo\venv\Output\Test.xml") 	# 生成xml文件,方法省略

通过以上处理后,可以得到如下xml文件。看起来要美观很多,但是和笔者想要得到的结果还有一定差距。返回来查看上述prettyXml方法,只能实现在节点的tail处增加换行和缩进处理,对于父节点CalConfigDefinitions、BoardConfigs、CalConfigs的“<…>”末尾处无法处理,这是该方法的不足之处,需要进一步处理。

<?xml version='1.0' encoding='utf-8'?>
<CalConfigDefinitions><BoardConfigs><BoardDef name="F02001-2" configs="F02001-2_LTE20" />
	</BoardConfigs>
	<CalConfigs><CalConfig name="F02001-2_LTE5" topology="407"><TxConfig txPathIdList="TX1,TX2" antennaNum="1,2" bwConst="LTE5" band="B41" fg="2" enableFb="false" txRefFreq="2590" listOfTxSweepFreqMhz="2498.5,2510.5,2520.5,2530.5,2540.5,2560.5,2580.5,2600.5,2620.5,2640.5,2660.5,2670.5,2680.5,2687.5" firstGainState="40" firstGainStatePowerLimitHigh="10" firstGainStatePowerLimitLow="-45" highestAllowedGainState="0" targetMaxPower="17" txDcLeakageLimit="-40" txIqImageLimit="-40" maxFreqSweepPeakToPeakDelta="10" rxFbDcLeakageLimitDbfs="-34" rxFbIqImageLimitDbc="-40" rxfbSignalDbfsMin="-20" rxfbSignalDbfsMax="0" txFreqSweepTargetReferencePowerDbm="17" txDigitalGainMaxDb="-3" txHighDcLeakageLimit="-43" txLowCutoffGainState="30" calDataAlsoAppliesTo="LTE10,LTE15,LTE20" txMonotonicCheckThresholdDb="-3" />
			<RxFb1AclrNoiseCal rxfbPathIdList="FB1,FB2" bwConst="LTE5" band="B41" fg="2" freq="2590" rxfbMaxGainState="16" />
			<RxConfig rxPathIdList="RX1,RX2" antennaNum="1,2" bwConst="LTE5" band="B41" fg="2" rxRefFreqMhz="2590" listOfRxSweepFreqMhz="2498.5,2510.5,2520.5,2530.5,2540.5,2560.5,2580.5,2600.5,2620.5,2640.5,2660.5,2670.5,2680.5,2687.5" rxGainStateList="0,1,2,3,4,5,6,7" rxSigGenPowersForGainState="-66,-59,-56,-51,-46,-41,-31,-21" rxDcLeakageLimitDbfs="-40" rxIqImageLimitDbc="-40" maxFreqSweepPeakToPeakDelta="10" rxSignalDbfsMin="-40" rxSignalDbfsMax="-20" calDataAlsoAppliesTo="LTE10,LTE15,LTE20" />
			<RxConfig rxPathIdList="NL1" antennaNum="3" bwConst="LTE20" band="B25" fg="3" rxRefFreqMhz="1960" listOfRxSweepFreqMhz="1930,1940,1945,1950,1955,1960,1965,1970,1975,1980,1985,1990,1995" rxGainStateList="0,1,2,3,4,5" rxSigGenPowersForGainState="-65,-57,-51,-40,-29,-18" rxDcLeakageLimitDbfs="-40" rxIqImageLimitDbc="-40" maxFreqSweepPeakToPeakDelta="10" rxSignalDbfsMin="-40" rxSignalDbfsMax="-20" />
		</CalConfig>
	</CalConfigs>
</CalConfigDefinitions>

网络上xml美化方法进一步优化

让我们站在大神们的肩膀上继续成长。既然prettyXml方法只能在tail处操作,那是否可以通过修改ElementTree.py源码实现"<…>"末尾处换行和缩进呢?

查找ElementTree.py源码,发现可以在 _serialize_xml方法中增加换行和缩进处理,修改后的代码如下(代码中还去除了节点属性的默认排序功能,读者可忽略此部分处理,如果感兴趣可以查看笔者的另一篇关于xml节点属性排序问题的博客)。

综上,通过修改_serialize_xml方法并结合使用prettyXml方法,便可以输出问题摘要章节中笔者想要得到的xml文件。

def _serialize_xml(write, elem, qnames, namespaces,
                   short_empty_elements, level=1, **kwargs):		# 增加level参数,用于递归操作,不同级别节点增加不同数量的“\t”
    tag = elem.tag
    text = elem.text
    if tag is Comment:
        write("<!--%s-->" % text)
    elif tag is ProcessingInstruction:
        write("<?%s?>" % text)
    else:
        tag = qnames[tag]
        if tag is None:
            if text:
                write(_escape_cdata(text))
            for e in elem:
                _serialize_xml(write, e, qnames, None,
                               short_empty_elements=short_empty_elements)
        else:
            write("<" + tag)
            items = list(elem.items())
            if items or namespaces:
                if namespaces:
                    for v, k in sorted(namespaces.items(),
                                       key=lambda x: x[1]):  
                        if k:
                            k = ":" + k
                        write(" xmlns%s=\"%s\"" % (
                            _escape_attrib(v)
                for k, v in items: 		# 【此处可不做关注】和源码比较,去掉了sorted方法,实现节点属性顺序的自定义
                    if isinstance(k, QName):
                        k = k.text
                    if isinstance(v, QName):
                        v = qnames[v.text]
                    else:
                        v = _escape_attrib(v)
                    write(" %s=\"%s\"" % (qnames[k], v))
            if text or len(elem) or not short_empty_elements:
                write(">\n" + level * "\t")  							# 在>处增加“\n”和“\t”
                if text:
                    write(_escape_cdata(text))
                for e in elem:
                    _serialize_xml(write, e, qnames, None,
                                   short_empty_elements=short_empty_elements,level=level+1)	# 增加level参数,低级别节点“\t”加1
                write("</" + tag + ">")
            else:
                write(" />")
    if elem.tail:
        write(_escape_cdata(elem.tail))

重写ElementTree.py源码思考

虽然已经实现了xml文件的美化,但是我们是通过修改 _serialize_xml和使用prettyXml来实现的,其实完全可以合并到一起,也就是将节点tail的处理也加入到_serialize_xml方法中,代码如下,输出xml的效果是一样的。

def _serialize_xml(write, elem, qnames, namespaces,
                   short_empty_elements, level=1, **kwargs):		# 增加level参数,用于递归操作,不同级别节点增加不同数量的“\t”
    tag = elem.tag
    text = elem.text
    if tag is Comment:
        write("<!--%s-->" % text)
    elif tag is ProcessingInstruction:
        write("<?%s?>" % text)
    else:
        tag = qnames[tag]
        if tag is None:
            if text:
                write(_escape_cdata(text))
            for e in elem:
                _serialize_xml(write, e, qnames, None,
                               short_empty_elements=short_empty_elements)
        else:
            write("<" + tag)
            items = list(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\"" % (
                            _escape_attrib(v)
                for k, v in items:  # 【此处可不做关注】和源码比较,去掉了sorted方法,实现节点属性顺序的自定义
                    if isinstance(k, QName):
                        k = k.text
                    if isinstance(v, QName):
                        v = qnames[v.text]
                    else:
                        v = _escape_attrib(v)
                    write(" %s=\"%s\"" % (qnames[k], v))
            if text or len(elem) or not short_empty_elements:
                write(">\n" + level * "\t")		# 在>处增加“\n”和“\t”
                if text:
                    write(_escape_cdata(text))
                elemList=list(elem)			# 将elem转化成列表
                for e in elem:				# 循环处理各个节点
                    if elemList.index(e) < (len(elemList) - 1):
                        e.tail = "\n" + "\t" * (level)		# 父节点的子节点换行和缩进处理(最后一个子节点除外)
                    else:
                        e.tail = "\n" + "\t" * (level - 1)	# 父节点的最后一个子节点换行和缩进处理
                    _serialize_xml(write, e, qnames, None,
                                   short_empty_elements=short_empty_elements,level=level+1)	# 增加level参数,低级别节点“\t”加1
                write("</" + tag + ">")
            else:
                write(" />")
    if elem.tail:
        write(_escape_cdata(elem.tail))
  1. 代码的优化永无止境,小白一枚,欢迎大家一起探讨;
  2. 此文档仅用于Python学习记录和交流,如能帮助到读者倍感荣幸。
在使用python中的xml.etree.ElementTree库解析xml文件时,默认不会做任何的换行和缩进处理,所有节点堆积在同一行,导致输出的xml文件阅读起来很不方便。本文通过增加换行和缩进来美化xml文件。
终于再也不需要在网页上排版xml了,早该写这东西了。 参考了这个博客 https://blog.csdn.net/xcookies/article/details/78647242 python3 程序,用法很简单 新建一个文本文件并改名为 pretty_xml.py 将下面的源码写进去保存 需要依赖包 lxml,如果没有就用以下命令安装依赖 pip install lxml 方法1...
@TOC今天第一次加入进来 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客: 全新的界面...
Element类型是一种灵活的容器对象,用于在内存中存储结构化数据。 [注意]xml.etree.ElementTree模块在应对恶意结构数据时显得并不安全。 每个element对象都具有以下属性:   1. tag:string对象,表示数据代表的种类。   2. attrib:dictionary对象,表示附有的属性。   3. text:string对象,表示elem... #from xml.etree import ElementTree as etree from xml.etree.ElementTree import Element from xml.etree.ElementTree import SubElement from xml.etree.ElementTree import ElementTree imagePath . def pretty_xml(element, indent, newline, level=0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行 if element: # 判断element是否有子元素
Python xml ElementTree 缩进(autoindent) 换行 参考链接:https://blog.csdn.net/saturn255/article/details/50791095 1.增加indent函数 2.增加调用:indent(root,0) defindent(elem, level=0): i ="\n"+ level*" " 在线XML美化格式化工具 美化格式化XML:压缩缩小xml 代码以美化、格式化、美化,使你的 xml 更易于阅读。语法高亮、自动完成功能也可以更轻松地编写代码。 美化格式化XML:压缩缩小xml 代码以美化、格式化、美化,使你的 xml 更易于阅读。语法高亮、自动完成功能也可以更轻松地编写代码。 https://toolgg.com/xml-beautifier.html 最近在写xml时由于涉及数据量比较大所以对性能跟内存有一定要求,在查询文章https://www.cnblogs.com/amengduo/p/9586382.html后决定选择cElementTreeElementTree为cElementTree编译前的源码),遇到了一些问题。但是在,新建的tag标签无换行缩进问题。 二:问题 1.更新或新建xml后遇到xml头部信息(<?xml version='1.0' encoding='utf-8'?>)未写...
详细介绍了如何从基础安装到实践应用掌握Hadoop和Spark两大数据处理框架。文章首先概述了Hadoop和Spark的定义与功能,然后详细描述了环境准备,包括Java和Python的安装。接着,文章分步骤指导如何下载、安装及配置Hadoop和Spark,并通过示例展示了如何进行基本的操作和任务处理,如在Hadoop上上传和读取文件,在Spark上执行Word Count任务。此外,指南还提供了常见问题的解决方案,并建议了进一步学习的方向,帮助读者深入理解和高效应用这两款工具。本文适合初学者,旨在帮助他们快速上手并掌握大数据处理的基本技能。 Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoop和Spark初学者指南Hadoo
CSDN-Ada助手: 非常感谢您分享这篇关于802.11-2020协议的学习笔记!您的知识分享将会帮助许多想要了解这方面知识的人。对于您提到的CCMP加密协议,我想建议您可以写一篇博客,深入解析CCMP的实现原理和安全性。对于安全这一话题,我们还可以探讨一些更实际的应用场景和防范方法。期待看到您的技术分享! 2023年博客之星「城市赛道」年中评选已开启(https://activity.csdn.net/creatActivity?id=10470&utm_source=blog_comment_city ), 博主的原力值在所在城市已经名列前茅,持续创作就有机会成为所在城市的 TOP1 博主(https://bbs.csdn.net/forums/blogstar2023?typeId=3152981&utm_source=blog_comment_city),更有丰厚奖品等你来拿~。