详解XML节点属性排序_xml节点排序-程序员宅基地

技术标签: github  python  源码分析  人工智能  Python  

1. 引入

为了对xml文件计算hash值,需要固定xml中item的属性顺序。否则相同xml但属性顺序不同,就会造成hash值不同(MITRE的Defense Evasion逃脱检测)。

就是想让如下两种写法: <a x="11" b="12" a="13"></a><a x="11" b="12" a="13"></a>,经过属性排序后,都变为 <a a="13" b="12" x="11"></a>。注意这里要解决的问题是对xml节点内部的属性排序,不是节点之间的排序。

如何用python实现“对xml节点中的属性进行排序”呢?

2. 问题分析

为了解决这个问题,查了xml解析的各种库,Google搜了关键词:

  • sort xml attributes alphabetically
  • canonical XML python
  • xml attribute sort python
  • python sort xml elements alphabetically
  • python xml attribute order
  • sort android manifest by python
  • python write xml with attribute order
  • python enforcing specific order for xml attributes
  • python enforcing order for xml attributes
  • python enforcing xml attributes order
  • xml c14n

看了各种资料,写代码做了一些测试,得出如下结论:

  1. 在XML中,本身是对属性没有顺序(order)要求的,也就是XML标准中认为XML的顺序无意义

  2. 只有把XML写到.XML文件中,属性的顺序是对最终XML的表现形式(hash值)有影响

  3. 往大一点说,这个问题属于XML规范化(XML Canonicalization,c14n)问题,W3C对这个c14n有专门的定义(见参考2)

  4. 然而,并没有什么成熟的python的库来实现c14n。有一些个人实现的c14n就是对tag做了规范化(简单的replace)。有一些库的老版本做过c14n但后来又deprecated了。其他一些搜到的方法也跑不通

  5. 根据如下链接,发现了一点蛛丝马迹:貌似 xml.etree.ElementTree 写xml到文件中时,会改变xml的attributes的顺序,而且根据回复看这个是将结果变为有序的。详见参考3.

3. 测试

  1. 属性无序的xml文件

创建一个名为easy1.xml的文件,内容如下,

<a x="11" b="12" a="13">
    <b y="21" c="22" d="23">
        <c t="31" f="32" e="33">
        </c>
    </b>
</a>
  1. python程序
import xml.etree.ElementTree as ET
tree = ET.parse('easy1.xml')# read xml from file
tree.write('tmp1.xml', encoding="UTF-8")# write xml content to file

程序只做了很简单的事情,读入xml文件,然后直接写到另一个文件中。

  1. 结果

程序运行后,得到的tmp1.xml文件中的内容如下

<a a="13" b="12" x="11">
    <b c="22" d="23" y="21">
        <c e="33" f="32" t="31">
        </c>
    </b>
</a>

可见最终结果是和原始easy1.xml文件内容不一样的,这里的各个节点内部的属性都变的有序了。

所以验证了第2部分第5个结论。

4. 为什么能做到有序

  1. 动态调试源码

单纯通过这样简单的验证,是不敢保证每一次这样操作都是有序的。有可能是ElementTree将xml解析为dict,这样因为dict的无序性,上一步的测试结果可能就是意外。

所以还需要查看下2中的源码实现原理,看看源码中是否做了属性有序的保证。通过(见参考1)中方法,找到如下源码:

  • /home/xxx/anaconda3/envs/xxxxx/lib/python3.7/xml/etree/ElementTree.py

打开这个文件,在其函数_serialize_xml中,如下位置,加入断点(或者print)进行动态调试:

            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,
                            _escape_attrib(v)
                            ))
                print(items)#这里加print调试
                for k, v in sorted(items):  # lexical order
                    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))

运行3中的python程序,可得输出结果(去掉非list的内容,因为这里只有sorted只对list有效)为:

[('x', '11'), ('b', '12'), ('a', '13')]
[('y', '21'), ('c', '22'), ('d', '23')]
[('t', '31'), ('f', '32'), ('e', '33')]

这里的输出结果,就是源码items的内容,从结果上也能看到这都是xml节点的属性。通过sorted排序后,这些属性就被写到外部文件中了。

所以,从源码调试中,验证了ElementTree的write操作,是会对xml的节点属性进行排序的,排序规则是(sorted函数自带的lexical order,也就是按字符串排序)。

5. 结论

  1. 用xml.etree.ElementTree来解析manifest文件,这个库在将xml写到外部文件时,会对属性排序后再写出去
  2. 很多其他库解析manifest会保持原始的attribute顺序,比如lxml

6. 参考

  1. 如何动态调试Python的第三方库,https://blog.csdn.net/ybdesire/article/details/54649211
  2. XML Canonicalization, https://www.w3.org/TR/xml-exc-c14n/
  3. https://stackoverflow.com/questions/14257978/elementtree-setting-attribute-order
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ybdesire/article/details/123747279

智能推荐

程序猿头头(js数组reverse,sort,concat,slice, splice)_splice/sort/reverse js-程序员宅基地

文章浏览阅读274次。reversereverse不是排序方法,它只是数组颠倒方法,可以将数组的顺序颠倒过来。// 书中的例子,只是作为反向排序讲解,不够全面let values = [1, 2, 3, 4, 5]; values.reverse();console.log(values); // [5,4,3,2,1]let numbers = [5,1,2,6,3];numbers.reverse();console.log(numbers); // [3, 6, 2, 1, 5]let chars =_splice/sort/reverse js

制作交叉编译工具链的方法总结(详细)_make[1]: *** [makefile:215: csu/subdir_lib] error -程序员宅基地

文章浏览阅读7.4k次,点赞3次,收藏11次。 网上这类文章比较多,但是都不是很具体,刚好有门课结课论文要写这个,所以就总结了一下。以下的过程都是在ubuntu7.10上实际运行过的。第一次在csdn上写文章。写的不好还请见谅。

app性能测试怎么做?内容全在这里了-程序员宅基地

文章浏览阅读3.2k次,点赞4次,收藏59次。!我个人整理了我这几年软件测试生涯整理的一些技术资料,包含:电子书,简历模块,各种工作模板,面试宝典,自学项目等。欢迎大家点击下方名片免费领取,千万不要错过哦。_app性能测试

Centos下安装mysql及常用mysql命令总结_怎么能让centos 有 mysql命令-程序员宅基地

文章浏览阅读496次。1.使用yum命令安装mysql[html] view plaincopy[root@bogon ~]# yum -y install mysql-server 2.设置开机启动[html] view plaincopy[root@bogon ~]#_怎么能让centos 有 mysql命令

171010 逆向-Reversing.kr(PEPassword)_reversing.krpepassword-程序员宅基地

文章浏览阅读819次。1625-5 王子昂 总结《2017年10月10日》 【连续第375天总结】 A. reversing.kr B.PEPassword给了两个文件,分别是加密过的和原版的 运行原版的发现弹窗Password是?????? IDA能看到这个password的运算,稍微跑一下就出来了 不过当然它不是真正的password啦╮(╯_╰)╭运行Packed.exe出现一个输入框,没有按钮 ID_reversing.krpepassword

计算机网络——应用层(2)-程序员宅基地

文章浏览阅读3.1k次,点赞103次,收藏103次。对计算机网络应用层Web和HTTP以及DNS进行分析

随便推点

python plt.subplot_Python Matplotlib subplot函数详解:创建子图-程序员宅基地

文章浏览阅读1.7k次。使用 Matplotlib 除可以生成包含多条折线的复式折线图之外,它还允许在一张数据图上包含多个子图。调用 subplot() 函数可以创建一个子图,然后程序就可以在子图上进行绘制。subplot(nrows, ncols, index, **kwargs) 函数的 nrows 参数指定将数据图区域分成多少行;ncols 参数指定将数据图区域分成多少列;index 参数指定获取第几个区域。sub..._python plt.subplot

关于QT调试操作步骤_qtcreator 如何debug-程序员宅基地

文章浏览阅读2.6k次。关于QT调试操作步骤 1.首先,用QtCreator打开Qt工程,然后点击左下角的电脑图标,再在弹出的菜单中选择“Debug”。 **2.接下来,在需要进行调试的代码部分设下断点。设断点的方法是在要设断点的代码行前的空白处点击鼠标。****3.如果想清除断点,则在该断点上再点击一下即可清除。**..._qtcreator 如何debug

什么是BIOS?为什么开机先从BIOS开始?以及操作系统启动过程-程序员宅基地

文章浏览阅读1.1w次,点赞9次,收藏67次。1、什么是BIOS?BIOS是英文bai"Basic Input Output System"的缩略词,直译过来后中文名称就是"基本输入输出系统"。其实,它是一组固化到计算机内主板上一个daoROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、系统设置信息、开机后自检程序和系统自启动程序。 其主要功能是为计算机提供最底层的、最直接的硬件设置和控制。有人认为既然BIOS是"程序",那它就应该是属于软件,感觉就像自己常用的Word或Excel。但也很多人不这么认为,因为它与一般的软件还是有一些区别_bios

Git 命令大全 && 常用的 35 个 Git 命令_git基本操作命令-程序员宅基地

文章浏览阅读1.2w次,点赞7次,收藏88次。add远程仓库: git remote add origin [email protected]:zhang/vue_shop.gitgit push推送到远程仓库: git push -u origin master 并以master 分支保存git status 检查项目状态 > git add . 添加所有文件到暂存区 > git commit –m “描述” 在本地提交 > git push 上传 > git pull 拉取远程代码 > git reset 回退..._git基本操作命令

2579页阿里P8Android学习笔记在互联网上火了,完整版开放下载(1)-程序员宅基地

文章浏览阅读735次,点赞23次,收藏14次。有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!后有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊![外链图片转存中…(img-65Xx6NTa-1712987646672)]

克隆虚拟机_无法为共享或远程虚拟机创建克隆-程序员宅基地

文章浏览阅读3.8w次,点赞2次,收藏11次。下面我们来讲一下如何通过已经创建好的虚拟机spark01克隆出spark02和spark03来,从而满足搭建大数据集群环境需要多台虚拟机的需求。完整克隆的虚拟机可以脱离原始虚拟机独立使用,不与原始虚拟机共享任何资源,是完全独立的虚拟机。链接克隆的虚拟机需要和原始虚拟机共享同一虚拟磁盘文件,不能脱离原始虚拟机独立运行。我们自然是要选择完整克隆的,我们需要的是完全独立的虚拟机。克隆虚拟机我们就讲到这里了。下一篇我们将讲一下如何。欢迎start,欢迎评论,欢迎指正。上一篇我们已经讲过了。_无法为共享或远程虚拟机创建克隆

推荐文章

热门文章

相关标签