xml地图|网站地图|网站标签 [设为首页] [加入收藏]

学习笔记,复杂的xml文件对比

2019-11-15 00:25栏目:可提现彩票app
TAG:

功能的设计初衷:
  处理复杂的xml对比,屏蔽同节点先后顺序的影响

difflib -帮助进行差异化比较

图片 1

主要涉及知识点:

这个模块提供的类和方法用来进行差异化比较,它能够生成文本或者html格式的差异化比较结果,如果需要比较目录的不同,可以使用filecmp模块。

Hallstatt 哈尔施塔特

1、ElementTree库 ------- xml解析:

class difflib.SequenceMatcher

人生苦短,我用Python。

    • 导入ElementTree,import xml.etree.ElementTree as ET
    • 解析Xml文件找到根节点:
    • 直接解析XML文件并获得根节点,tree = ET.parse('country_data.xml') root = tree.getroot()
    • 解析字符串,root = ET.fromstring(country_data_as_string)
    • 遍历根节点可以获得子节点,然后就可以根据需求拿到需要的字段了,如:<APP_KEY channel = 'CSDN'> hello123456789 </APP_KEY>
      • tag,即标签,用于标识该元素表示哪种数据,即APP_KEY
      • attrib,即属性,用Dictionary形式保存,即{'channel' = 'CSDN'}
      • text,文本字符串,可以用来存储一些数据,即hello123456789
      • tail,尾字符串,并不是必须的,例子中没有包含。

这是可以用来比较任何类型片段的类,只要比较的片段是可hash的,都可以用来比较,使用非常灵活。他源于1980,s的“完形匹配算法”,并且进行了一系列的优化和改进。

起初,这篇文章是打算来写 XPath 的,可是后来一想,我需要的仅是 XPath 的一部分,我仅仅是打算在写爬虫的时候,抓取特定数据的,并且这是需要结合 lxml 的,So ,索性就来写 lxml 来了。(lxml supports XPath 1.0, XSLT 1.0 and the EXSLT extensions through libxml2 and libxslt in a standards compliant way.这是教程上的一段话,但是XPath现在是有2.0版本的。)

2、difflib库 ------- 提供的类和方法用来进行序列的差异化比较,它能够比对文件并生成差异结果文本或者html格式的差异化比较页面

通过对算法的复杂度比较,它由于原始的完形匹配算法,在最坏情况下有n的平方次运算,在最好情况下,具有线性的效率。

关于教程方面官方网站上给出了三个教程:

这里使用了类difflib.HtmlDiff,用来创建一个html表格展示文件差异,他既可以进行全文本展示,也可以只展示上下文不同。

它具有自动垃圾启发式,可以将重复超过片段1%或者重复200次的字符作为垃圾来处理。可以通过将autojunk设置为false关闭该功能。

  • the lxml.etree tutorial for XML processing 这个是官方的教程。
  • John Shipman's tutorial on Python XML processing with lxml 这个是 New Mexico Tech 大学的一个教程。嗯 ,有点久了,最后更新时间是 2013-08-24 ,当时应该是 3.2 版本的。不过易读性还是比官方的强。
  • Fredrik Lundh's tutorial for ElementTree 这个是 Fredrik Lundh 维护的一个第三方库,后来也被整合到 Python 标准库 xml 中了。这个没时间可以不看,我感觉用不到应该。

其构造函数如下:

autojunk 参数新增于2.7.1版本。

lxml is the most feature-rich and easy-to-use library for processing XML and HTML in the Python language.

__init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)

class difflib.Differ

lxml 是提供了一个 Pythonic API ,并且她也是几乎完全兼容 ElementTree API 的。lxml 的开发团队也是力求减少开发者的学习成本,不过 lxml 的教程感觉一点都不友好。

      • tabsize表示制表符代表的空格个数,默认为8
      • wrapcolumn,可选参数,用来设置多少个字符时自动换行,默认None,为None时表示不自动换行(重点:可以让html显示更美观)
      • linejunk 和 charjunk,可选参数,在ndiff()中使用,

这个类用来比较文本里的行,并且产生可阅读的差异化结果。

在看官方教程的时候,发现了一些小疑惑:

公共方法(生成一个包含表格的html文件,其内容是用来展示差异):

它用以下符号来表示不同

lxml 模块并不仅仅是我们在网上搜到的 etree ,lxml 下面还有很多的模块,有 etree 、html 、cssselect 等众多模块。另外我也看到了 BeautifulSoup 。

make_file(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])

Code

Meaning

'- '

仅在片段1中存在

' '

仅在片段2中存在

' '

片段1和2中都存在

'? '

存在疑问的

lxml can make use of BeautifulSoup as a parser backend, just like BeautifulSoup can employ lxml as a parser.

lxml interfaces with BeautifulSoup through the lxml.html.soupparser module.

      • fromlines 和tolines,用于比较的内容,格式为字符串组成的列表
      • fromdesc 和 todesc,可选参数,对应的fromlines,tolines的差异化文件的标题,默认为空字符串
      • context 和 numlines,可选参数,context 为True时,只显示差异的上下文,为false,显示全文,numlines默认为5,当context为True时,控制展示上下文的行数,当context为false时,控制不同差异的高亮之间移动时“next”的开始位置(如果设置为0,当移动懂顶端时,超链接会丢失引用地址)

标识为?需要你通过人工的方式仔细比较他们的不同,他们产生的原因是源于混乱的制表符

BeautifulSoup 可以将 lxml 作为解析器,这个我是知道的,但是 lmxl.html.soupparser 可以调用 BeautifulSoup 我就不明白了。刚开始以为理解错误,但是确实在源码中找到的证据,soupparser 模块中引入了 BeautifulSoup ,并且也调用了该函数。

3、platform库 -------- 获取当前系统

class difflib.HtmlDiff

两者之间可以相互调用,并且两者之间的函数也是很相似的,就连 css 选择器两个也都有。有意思了。难道 BeautifulSoup 是 lxml 的一部分?

4、logger库 -------- 如果使用robot framework,可以看到明显区别,可以定制日志log显示

这个类用来创建一个html表格(或者包含html表格的文件)用来展示文件差异。他既可以进行全文本展示,也可以只展示上下文不同。

BeautifulSoup 是在 2004 年发布的。lxml 大约是在 2005 年发布。

robot framework的体验还不错,大概是因为其测试报告已经可以满足正常需要,很少有人会想去修改或者增加自己想要展示的内容,比如增加一个超链接,展示更多的内容,所以这部分花了很长时间均没有在网上找到相关资料,最后只能阅读源码。

这个类的构造函数如下:

2008 年,lxml v2.0 发布,lxml.html 添加到库中;在 v2.0.3 版本中 lxml.html.soupparser 才出现。

遗憾与待优化:

__init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)

直到 2012 年 bs4 发布,BeautifulSoup 才可以选择从内置解析器、html5lib 、lxml 这三个中选一个作为解析器,而之前版本使用的是却是另一个。

  其中有一部分内容,原先准备采用自循环的方式处理,但是过程中的数据传输逻辑容易错乱,以后会考虑把这部分优化一下。

tabsize表示制表符代表的空格个数,默认为8

显然,这两个是两码事。可是两者之间的区别以及联系是什么(因为相似度有点高),特定的情况下又该做出何种选择?这个疑问先立在这里,容我以后回答。我所知道的是 BeautifulSoup 强大检测编码能力,并且能够以 utf-8 形式输出;lxml 具有速度飞起的文本解析力。

##############################以下是代码部分,附件文件可以拖到本地执行并查看结果##################################################

  1 # coding=utf-8
  2 import re
  3 import xml.etree.ElementTree as ET  #解析xml的库
  4 import difflib   #文件对比库
  5 import datetime  #时间库
  6 import platform  #获取系统的库window、linux...
  7 import os
  8 from robot.api import logger    #不需要的话可以注释掉:robot framework框架脚本运行时会产生日志,可以利用这个库定制log
  9 
 10 # listafter:将解析后的xml,转换成按序排列的list:(tag,attrib,(tag,attrib,text))
 11 # 此方法是被下面一个方法xmltolist()调用的,想知道具体结果,可以使用下面的方法打印解析后的结果
 12 def listafter(listcom1):
 13     listcomarr1 = []
 14     text1 = []
 15     listcomarr1.append(listcom1.tag)
 16     listcomarr1.append(listcom1.attrib)
 17     if len(listcom1) > 0:
 18         for listcom2 in listcom1:
 19             listcomarr2 = []
 20             text2 = []
 21             listcomarr2.append(listcom2.tag)
 22             listcomarr2.append(listcom2.attrib)
 23             if len(listcom2) > 0:
 24                 for listcom3 in listcom2:
 25                     listcomarr3 = []
 26                     text3 = []
 27                     listcomarr3.append(listcom3.tag)
 28                     listcomarr3.append(listcom3.attrib)
 29                     if len(listcom3) > 0:
 30                         for listcom4 in listcom3:
 31                             listcomarr4 = []
 32                             text4 = []
 33                             listcomarr4.append(listcom4.tag)
 34                             listcomarr4.append(listcom4.attrib)
 35                             if len(listcom4) > 0:
 36                                 for listcom5 in listcom4:
 37                                     listcomarr5 = []
 38                                     text5 = []
 39                                     listcomarr5.append(listcom5.tag)
 40                                     listcomarr5.append(listcom5.attrib)
 41                                     if len(listcom5) > 0:
 42                                         for listcom6 in listcom5:
 43                                             listcomarr6 = []
 44                                             text6 = []
 45                                             listcomarr6.append(listcom6.tag)
 46                                             listcomarr6.append(listcom6.attrib)
 47                                             if len(listcom6) > 0:
 48                                                 for listcom7 in listcom6:
 49                                                     listcomarr7 = []
 50                                                     text7 = []
 51                                                     listcomarr7.append(listcom7.tag)
 52                                                     listcomarr7.append(listcom7.attrib)
 53                                                     if len(listcom7) > 0:
 54                                                         for listcom8 in listcom7:
 55                                                             listcomarr8 = []
 56                                                             text8 = []
 57                                                             listcomarr8.append(listcom8.tag)
 58                                                             listcomarr8.append(listcom8.attrib)
 59                                                             if len(listcom8) > 0:
 60                                                                 for listcom9 in listcom8:
 61                                                                     listcomarr9 = []
 62                                                                     text9 = []
 63                                                                     listcomarr9.append(listcom9.tag)
 64                                                                     listcomarr9.append(listcom9.attrib)
 65                                                                     # Start:判断是否需要继续递归
 66                                                                     if len(listcom9) > 0:
 67                                                                         for listcom10 in listcom9:
 68                                                                             listcomarr10 = []
 69                                                                             text10 = []
 70                                                                             listcomarr10.append(listcom10.tag)
 71                                                                             listcomarr10.append(listcom10.attrib)
 72                                                                             listcomarr10.append([listcom10.text])
 73                                                                             text9.append(listcomarr10)
 74                                                                     else:
 75                                                                         text9.append(listcom9.text)
 76                                                                     # End:判断是否需要继续递归
 77                                                                     # list二维数组排序
 78                                                                     text9 = sorted(text9)
 79                                                                     listcomarr9.append(text9)
 80                                                                     text8.append(listcomarr9)
 81                                                             else:
 82                                                                 text8.append(listcom8.text)
 83                                                             text8 = sorted(text8)
 84                                                             listcomarr8.append(text8)
 85                                                             text7.append(listcomarr8)
 86                                                     else:
 87                                                         text7.append(listcom7.text)
 88                                                     text7 = sorted(text7)
 89                                                     listcomarr7.append(text7)
 90                                                     text6.append(listcomarr7)
 91                                             else:
 92                                                 text6.append(listcom6.text)
 93                                             text6 = sorted(text6)
 94                                             listcomarr6.append(text6)
 95                                             text5.append(listcomarr6)
 96                                     else:
 97                                         text5.append(listcom5.text)
 98                                     text5 = sorted(text5)
 99                                     listcomarr5.append(text5)
100                                     text4.append(listcomarr5)
101                             else:
102                                 text4.append(listcom4.text)
103                             text4 = sorted(text4)
104                             listcomarr4.append(text4)
105                             text3.append(listcomarr4)
106                     else:
107                         text3.append(listcom3.text)
108                     text3 = sorted(text3)
109                     listcomarr3.append(text3)
110                     text2.append(listcomarr3)
111             else:
112                 text2.append(listcom2.text)
113             text2 = sorted(text2)
114             listcomarr2.append(text2)
115             text1.append(listcomarr2)
116     else:
117         text1.append(listcom1.text)
118     text1 = sorted(text1)
119     listcomarr1.append(text1)
120     return listcomarr1
121 
122 # 将xml内容转换成按序排列的list,返回值有3个:处理后的spmlxmllist、不需要处理的头部spmlstart、不需要处理的尾部spmlend
123 # spmlstart、spmlend是为了控制不需要处理的头部和尾部,提高处理效率
124 def xmltolist(spml):
125     if spml.find("<spml:") != -1:
126         startnum = re.search(r'<spml:[^>]*>', spml).span()[1]
127         endnum = spml.rfind("</spml:")
128         spmlstart = spml[:startnum].strip()
129         spmlend = spml[endnum:].strip()
130         spmlxml = '''<spml:modifyRequest xmlns:spml='{spml}' xmlns:subscriber="{subscriber}" xmlns:xsi="{xsi}">n%s</spml:modifyRequest>''' % (
131             spml[startnum:endnum].strip())
132     elif spml.find("<PlexViewRequest") != -1:
133         startnum = re.search(r'<PlexViewRequest[^>]*>', spml).span()[1]
134         endnum = spml.rfind("</PlexViewRequest>")
135         spmlstart = spml[:startnum].strip()
136         spmlend = spml[endnum:].strip()
137         spmlxml = '''<PlexViewRequest>n%s</PlexViewRequest>''' % (spml[startnum:endnum].strip())
138     else:
139         spmlstart = ""
140         spmlend = ""
141         spmlxml = spml
142     # print spmlstart
143     # print endspml
144     # print spmlxml
145     tree = ET.fromstring(spmlxml)
146     spmlxmllist = listafter(tree)
147     return spmlxmllist, spmlstart, spmlend
148 
149 # 将xmltolist处理形成的spmlxmllist再回头变成xml(xml中,同节点的内容已被按需排列)
150 def listtoxml(spmllist1):
151     kong = "  "
152     spmltag1 = spmllist1[0]
153     spmlattrib1 = ""
154     bodyxml1 = ""
155     if spmllist1[1] != {}:
156         for key, value in spmllist1[1].items():
157             spmlattrib1  = " %s='%s'" % (key, value)
158     startxml1 = "<%s%s>" % (spmltag1, spmlattrib1)
159     endxml1 = "</%s>" % (spmltag1)
160     spmlxml1 = ""
161     if isinstance(spmllist1[2][0], list):
162         spmlxml2 = ""
163         for spmllist2 in spmllist1[2]:
164             spmltag2 = spmllist2[0]
165             spmlattrib2 = ""
166             bodyxml2 = ""
167             if spmllist2[1] != {}:
168                 for key, value in spmllist2[1].items():
169                     spmlattrib2  = " %s='%s'" % (key, value)
170             startxml2 = "<%s%s>" % (spmltag2, spmlattrib2)
171             endxml2 = "</%s>" % (spmltag2)
172             if isinstance(spmllist2[2][0], list):
173                 spmlxml3 = ""
174                 for spmllist3 in spmllist2[2]:
175                     spmltag3 = spmllist3[0]
176                     spmlattrib3 = ""
177                     bodyxml3 = ""
178                     if spmllist3[1] != {}:
179                         for key, value in spmllist3[1].items():
180                             spmlattrib3  = " %s='%s'" % (key, value)
181                     startxml3 = "<%s%s>" % (spmltag3, spmlattrib3)
182                     endxml3 = "</%s>" % (spmltag3)
183                     if isinstance(spmllist3[2][0], list):
184                         spmlxml4 = ""
185                         for spmllist4 in spmllist3[2]:
186                             spmltag4 = spmllist4[0]
187                             spmlattrib4 = ""
188                             bodyxml4 = ""
189                             if spmllist4[1] != {}:
190                                 for key, value in spmllist4[1].items():
191                                     spmlattrib4  = " %s='%s'" % (key, value)
192                             startxml4 = "<%s%s>" % (spmltag4, spmlattrib4)
193                             endxml4 = "</%s>" % (spmltag4)
194                             if isinstance(spmllist4[2][0], list):
195                                 spmlxml5 = ""
196                                 for spmllist5 in spmllist4[2]:
197                                     spmltag5 = spmllist5[0]
198                                     spmlattrib5 = ""
199                                     bodyxml5 = ""
200                                     if spmllist5[1] != {}:
201                                         for key, value in spmllist5[1].items():
202                                             spmlattrib5  = " %s='%s'" % (key, value)
203                                     startxml5 = "<%s%s>" % (spmltag5, spmlattrib5)
204                                     endxml5 = "</%s>" % (spmltag5)
205                                     if isinstance(spmllist5[2][0], list):
206                                         spmlxml6 = ""
207                                         for spmllist6 in spmllist5[2]:
208                                             spmltag6 = spmllist6[0]
209                                             spmlattrib6 = ""
210                                             bodyxml6 = ""
211                                             if spmllist6[1] != {}:
212                                                 for key, value in spmllist6[1].items():
213                                                     spmlattrib6  = " %s='%s'" % (key, value)
214                                             startxml6 = "<%s%s>" % (spmltag6, spmlattrib6)
215                                             endxml6 = "</%s>" % (spmltag6)
216                                             if isinstance(spmllist6[2][0], list):
217                                                 spmlxml7 = ""
218                                                 for spmllist7 in spmllist6[2]:
219                                                     spmltag7 = spmllist7[0]
220                                                     spmlattrib7 = ""
221                                                     bodyxml7 = ""
222                                                     if spmllist7[1] != {}:
223                                                         for key, value in spmllist7[1].items():
224                                                             spmlattrib7  = " %s='%s'" % (key, value)
225                                                     startxml7 = "<%s%s>" % (spmltag7, spmlattrib7)
226                                                     endxml7 = "</%s>" % (spmltag7)
227                                                     if isinstance(spmllist7[2][0], list):
228                                                         spmlxml8 = ""
229                                                         for spmllist8 in spmllist7[2]:
230                                                             spmltag8 = spmllist8[0]
231                                                             spmlattrib8 = ""
232                                                             bodyxml8 = ""
233                                                             if spmllist8[1] != {}:
234                                                                 for key, value in spmllist8[1].items():
235                                                                     spmlattrib8  = " %s='%s'" % (key, value)
236                                                             startxml8 = "<%s%s>" % (spmltag8, spmlattrib8)
237                                                             endxml8 = "</%s>" % (spmltag8)
238                                                             if isinstance(spmllist8[2][0], list):
239                                                                 spmlxml9 = ""
240                                                                 for spmllist9 in spmllist8[2]:
241                                                                     spmltag9 = spmllist9[0]
242                                                                     spmlattrib9 = ""
243                                                                     bodyxml9 = ""
244                                                                     if spmllist9[1] != {}:
245                                                                         for key, value in spmllist9[1].items():
246                                                                             spmlattrib9  = " %s='%s'" % (key, value)
247                                                                     startxml9 = "<%s%s>" % (spmltag9, spmlattrib9)
248                                                                     endxml9 = "</%s>" % (spmltag9)
249                                                                     if isinstance(spmllist9[2][0], list):
250                                                                         spmlxml10 = ""
251                                                                         for spmllist10 in spmllist9[2]:
252                                                                             spmltag10 = spmllist10[0]
253                                                                             spmlattrib10 = ""
254                                                                             bodyxml10 = ""
255                                                                             if spmllist10[1] != {}:
256                                                                                 for key, value in spmllist10[1].items():
257                                                                                     spmlattrib10  = " %s='%s'" % (
258                                                                                         key, value)
259                                                                             startxml10 = "<%s%s>" % (
260                                                                                 spmltag10, spmlattrib10)
261                                                                             endxml10 = "</%s>" % (spmltag10)
262                                                                             bodyxml10 = spmllist10[2][0]
263                                                                             spmlxml10  = "n%s%s%s%s" % (
264                                                                                 kong * 9, startxml10, bodyxml10,
265                                                                                 endxml10)
266                                                                         spmlxml9  = "n%s%s%sn%s%s" % (
267                                                                             kong * 8, startxml9, spmlxml10, kong * 8,
268                                                                             endxml9)
269                                                                     else:
270                                                                         bodyxml9 = spmllist9[2][0]
271                                                                         spmlxml9  = "n%s%s%s%s" % (
272                                                                             kong * 8, startxml9, bodyxml9, endxml9)
273                                                                 spmlxml8  = "n%s%s%sn%s%s" % (
274                                                                     kong * 7, startxml8, spmlxml9, kong * 7, endxml8)
275                                                             else:
276                                                                 bodyxml8 = spmllist8[2][0]
277                                                                 spmlxml8  = "n%s%s%s%s" % (
278                                                                     kong * 7, startxml8, bodyxml8, endxml8)
279                                                         spmlxml7  = "n%s%s%sn%s%s" % (
280                                                             kong * 6, startxml7, spmlxml8, kong * 6, endxml7)
281                                                     else:
282                                                         bodyxml7 = spmllist7[2][0]
283                                                         spmlxml7  = "n%s%s%s%s" % (
284                                                             kong * 6, startxml7, bodyxml7, endxml7)
285                                                 spmlxml6  = "n%s%s%sn%s%s" % (
286                                                     kong * 5, startxml6, spmlxml7, kong * 5, endxml6)
287                                             else:
288                                                 bodyxml6 = spmllist6[2][0]
289                                                 spmlxml6  = "n%s%s%s%s" % (kong * 5, startxml6, bodyxml6, endxml6)
290                                         spmlxml5  = "n%s%s%sn%s%s" % (
291                                             kong * 4, startxml5, spmlxml6, kong * 4, endxml5)
292                                     else:
293                                         bodyxml5 = spmllist5[2][0]
294                                         spmlxml5  = "n%s%s%s%s" % (kong * 4, startxml5, bodyxml5, endxml5)
295                                 spmlxml4  = "n%s%s%sn%s%s" % (kong * 3, startxml4, spmlxml5, kong * 3, endxml4)
296                             else:
297                                 bodyxml4 = spmllist4[2][0]
298                                 spmlxml4  = "n%s%s%s%s" % (kong * 3, startxml4, bodyxml4, endxml4)
299                         spmlxml3  = "n%s%s%sn%s%s" % (kong * 2, startxml3, spmlxml4, kong * 2, endxml3)
300                     else:
301                         bodyxml3 = spmllist3[2][0]
302                         spmlxml3  = "n%s%s%s%s" % (kong * 2, startxml3, bodyxml3, endxml3)
303                 spmlxml2  = "n%s%s%sn%s%s" % (kong * 1, startxml2, spmlxml3, kong * 1, endxml2)
304             else:
305                 bodyxml2 = spmllist2[2][0]
306                 spmlxml2  = "n%s%s%s%s" % (kong * 1, startxml2, bodyxml2, endxml2)
307         spmlxml1  = "n%s%sn%s" % (startxml1, spmlxml2, endxml1)
308     else:
309         bodyxml1 = spmllist1[2][0]
310         spmlxml1  = "n%s%s%s" % (startxml1, bodyxml1, endxml1)
311     return spmlxml1
312 
313 # 将startspml, xmlspml, endspml组合起来,其中有一部分内容需要根据实际情况处理
314 def regroupspml(startspml, xmlspml, endspml):
315     xmlspml = str(xmlspml).replace("{{", "").replace("}}", ":").strip().splitlines()
316     if endspml != "":
317         startspml = str(startspml.strip()).replace(""", "'")
318         startspml = re.sub("  >", ">", startspml)
319         startspml = startspml.splitlines()
323         endspml = str(endspml.strip()).splitlines()
324         spmlxmlcom = startspml   xmlspml[1:-1]   endspml
325     else:
326         spmlxmlcom = xmlspml
327     return spmlxmlcom
328 
329 # 对按序排列的xml进行内容比对,生成html文件,可以很直接的看出内容区别
330 def diffspml(spmlxml1, spmlxml2):
331     spmlxmllist1, spmlstart1, spmlend1 = xmltolist(spmlxml1)
332     spmlxmllist2, spmlstart2, spmlend2 = xmltolist(spmlxml2)
333     spmlxmlcom1 = listtoxml(spmlxmllist1)
334     spmlxmlcom2 = listtoxml(spmlxmllist2)
335     spmlxmlcom1 = regroupspml(spmlstart1, spmlxmlcom1, spmlend1)
336     spmlxmlcom2 = regroupspml(spmlstart2, spmlxmlcom2, spmlend2)
337     # print spmlstart1
338     # print spmlend1
339     if spmlxmlcom1 == spmlxmlcom2:
340         return 0
341     else:
342         global diffspmNum
343         global outputhtml_dir
344         try:
345             diffspmNum  = 1
346         except:
347             diffspmNum = 1
348             system = platform.system()
349             if ('Windows' in system):
350                 outputhtml_dir = "c:/RobotLog"
351             else:
352                 outputhtml_dir = "/tmp/RobotLog"
353             outputhtml_dir = "%s/%s" % (outputhtml_dir, datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))
354             os.makedirs(outputhtml_dir)
355         Loghtmldir = "%s/%s.html" % (outputhtml_dir, diffspmNum)
356         # logger.write("<a href="%s">%s</a>" % (Loghtmldir, Loghtmldir), "HTML")
357         hd = difflib.HtmlDiff(8,65)
358         with open(Loghtmldir, 'w') as fo:
359             fo.write(hd.make_file(spmlxmlcom1, spmlxmlcom2))
360             fo.close()
361         return Loghtmldir

wrapcolumn,可选参数,用来设置多少个字符时自动换行,默认None,为None时表示不自动换行

本篇文章的介绍顺序是 lxml.etreeXPathlxml.html

 

linejunkcharjunk,可选参数,在ndiff()中使用,

lxml.etree

作为一个强大的 xml 处理模块,该有的功能她都是有的。

若操作一个 XML ,首先要能读写,能将字符串或流读进来解析成 ElementTree ,又能将 ElementTree 转换为字符串或流。在这方面 lxml 提供了几个可用的函数:

  • etree.fromstring( string )

    将 string 解析为 Element 或者 ElementTree 。

  • etree.parse( file )

    将文件或者是 file_like 对象解析为 ElementTree (not an Element object),因为 parse() 一般解析整篇文档,字符串解析函数一般只解析片段。其中 file 还可以是 HTTP/FTP URL ,也就是说,file 应该是一个 Bytes 流。不过 libxml2 中的 HTTP/FTP client 比较简单,所以可以考虑使用第三方库。

  • XML( text ) / HTML( text )

    行为比较像 fromstring() ,比较直接的对 XML 和 HTML 文档进行特定解析,可以修改解析器 parser 参数,不同的解析器设置区别还是蛮大的。其中 parser 可以由相应的 XMLParser() / HTMLParser() 函数生成,可设置项有很多不仅限于 encoding 、recover 、remove_blank_text 、remove_comments ,但是默认值是存在不同的。比如 recover 在 XML 中是 False ,而在 HTML 中是 True 。在 HTML 中会使用 libxml2 的 recover 算法对不盒饭的标签进行修复。

  • etree.tostring( elt )

    将一个 Element 或者 ElementTree 转换为 string 形式。这里面有几个可选参数:pretty_print=False 表示是否格式化提高可读性;method="xml" 选择输出后的文档格式,不同的选择,做的修改也不相同,可选参数有 xml 、html 、text (文本内容不包括标签,就是纯文本内容,tail也是) 、c14n (规范化 xml );encoding=None 表示以什么编码的字符串输出,在无 xml 文档声明情况下默认是 ASCⅡ ,可通过 encoding=None 进行修改,但是如果所改编码不是 utf-8 兼容,那么将会启用默认声明。

  • ElementTree.write( file )

    这个是 ElementTree 特有的方法,是将 ElementTree 写到 a file, a file-like object, or a URL (via FTP PUT or HTTP POST) 。可选参数和 tostring() 差不多,也有不同。

剩下就是操作了,增删查改一样也不少,而查找是剩下三个的基础。

etree 对于每种元素都有一个创建函数,比如 Element() 、ElementTree() 、SubElement() 以及 Comment() 。基本所有的函数都是基于这些实例对象的,lxml 的 API 是比较 Pythonic 的,Element 的行为和 list 比较像可以使用 len() 函数切片等,Element 的 attrib 就是一个 dist ;其中 Element 实例拥有 41 个属性和方法,包含了所有:

append() insert()

clear() remove()

find*() get*() iter*() xpath()

set() 以及属性 .tag .attrib .text .tail等的操作

ElementTree 实例拥有的方法较少,常用的大概有 7 种,主要是查找find*() get*() xpath()

Element 的属性介绍:

  • .tag

    元素的名称

  • .attrib

    一个包含元素属性的字典,key 是属性名,value 是对应的值。

  • .text

    Element 的文本均为直接子文本,不包含子元素中的文本,这其中又包含两部分 .text 和 .tail 。.text 是第一个子元素标签之前的,如果没有则为 None 。

  • .tail

    .tail 为 Element 的关闭标签之后的文本,并且是在下一个兄弟子标签之前的部分。没有则为 None 。

Element 的方法介绍:

  • append( child )

    添加一个新的子节点(可以是 Element 、Comment)到当前 Element 中。

  • insert( index, elt)

    将子元素 elt 插入到指定位置,这个 index 的随意性比较大,如果是正数但是超过了最大值,那么 lxml 会直接将这个元素插到末尾,如果是负数,但是这个负数所指位置不存在,那么就插到末尾,这个负数的位置计算规则和列表的那个不太一样,不知道正确的规律是什么,但是经过测试,-n所插的位置,后面有 n (以变化前计算)个元素。如果对 Element 中的子元素执行 insert() 操作,那么子元素位置会按 index 指定的变换。

  • clear()

    调用该函数,将移除所有内容 .attrib 将被移除 .text 和 .tail 将被设置为 None 所有的子节点将被删除。

  • remove( child )

    将子节点 child 从Element 中移除 ,如果child 不是 Element 的子节点,将会引发 ValueError 异常。

  • find( path )

    从 Element 的子元素及后代元素中查找第一个符合 path 的 subelement 。如果没有返回 None 。

    ElementPath 是 ElementTree 自带的一个 XPath-like 的路径语言,和 XPath 差不太多,主要区别是 ElementPath 能用 {namespace}tag,但是 ElementPath 不能使用值比较和函数。

  • findall( path )

    返回一个匹配的 Element 的列表。

  • findtext( path, default=None )

    返回第一个匹配元素的 .text 内容,如果存在匹配,但是没有 .text 内容,那么将返回一个空字符串,如果没有一个匹配的元素,那么将会返回一个 None ,但是有 default 参数,返回 default 所指定的。

  • get( key, default=None )

    返回字符串形式的 属性 key 的值,没有返回 None 或者 default 指定的。

  • getchildren()

    返回一个包含 Element 子元素的列表。

  • getiterator( tag=None, *tags )

    返回元素的一个生成器,返回元素类别取决于参数 tag ,生成顺序是in document order (depth first pre-order) 深度优先的先根遍历。如果没有参数的话,则第一个就是元素本身。如果想使用一个高效的生成器,可以使用 .iter() 。

  • getroottree()

    返回该元素的 ElementTree 。

  • iter( tag=None, *tags )

    过滤特定标签,生成迭代器。默认情况下,iter() 迭代所有的节点,包括PI(处理指令) 、Comment(注释) 等,如果只想迭代标签元素,可以使用 Element factory 做参数e.iter(tag = etree.Element)

  • iterfind( path )

    迭代所有匹配 ElementPath 的 Element 。

  • itertext( tag=None, *tags, with_tail=True )

    迭代 Element 元素的文本内容,with_tail 参数决定是否迭代子元素的 tail 。Element 的tail 不会进行迭代。

  • iterancestors( tag=None )

    如果忽略参数,那么将会迭代所有先辈,加标签名可以只迭代该标签先辈。

  • iterchildren( reversed=False, tag=None )

    通过设置 reversed=True 可以以反向的顺序迭代子元素。

  • itersiblings( preceding=False )

    迭代 Element 之后的兄弟元素,可以通过设置 preceding=True 仅迭代 Element 之前的兄弟元素。

  • iterdescendants( tag=None )

    同 iterancestors()

  • items()

    返回由元素属性的键值所构成的( name, value)元组的列表。

  • keys()

    返回一个没有特定顺序的元素属性名的列表。

  • set(A, V)

    创建或者改变属性 A 的值为 V。

  • xpath()

ElementTree 方法介绍:

没有介绍的方法,是前面的类似,或者已经介绍过。

  • find( path )

  • findall( path )

  • findtext( path )

  • getiterator( tag=None, *tags )

  • getroot()

    获得 ElementTree 的 root 元素,一般情况下是树的根节点的 Element 的实例,但是 ElementTree 是经没有任何东西创建出来的,将返回 None 。

  • xpath()

  • write()

 

#############################################以上是代码部分#################################################################

 1 spmlxml1='''
 2 <PlexViewRequest SessionId="${sessionid}" ProvisioningGroup="volte" Command="ed-ngfs-subscriber-v2"><SubParty><PrimaryPUID> 86${ISDN}@${domain}</PrimaryPUID><PartyId> 86${ISDN}</PartyId></SubParty><SeqRinging><RingingList>null^null^true^true^10^false` 86${msisdn1}^STANDARD^true^true^10^false</RingingList><DefaultAnswerTimeout>10</DefaultAnswerTimeout><Send181Mode>TAS_181_NONE</Send181Mode><Activated>true</Activated><PublicUID> 86${ISDN}@${domain}</PublicUID><Assigned>true</Assigned></SeqRinging></PlexViewRequest>
 3 '''
 4 spmlxml2='''
 5 <PlexViewRequest SessionId="${sessionid}" ProvisioningGroup="volte" Command="ed-ngfs-subscriber-v2">
 6    <SubParty>
 7       <PrimaryPUID> 86${ISDN}@${domain}</PrimaryPUID>
 8       <PartyId> 86${ISDN}</PartyId>
 9    </SubParty>
10    <SeqRinging>
11       <RingingList>null^null^true^true^10^false` 86${msisdn1}^STANDARD^true^true^10^false</RingingList>
12       <DefaultAnswerTimeout>10</DefaultAnswerTimeout>
13       <Send181Mode>TAS_180_NONE</Send181Mode>
14       <Activated>true</Activated>
15       <PublicUID> 86${ISDN}@${domain}</PublicUID>
16    </SeqRinging>
17 </PlexViewRequest>
18 '''
19 print diffspml(spmlxml1, spmlxml2)

#####################################以上列出来了本公司使用的xml格式(还可以更复杂),方法中有部分内容是根据本身需要,特别处理的####################################

这个类的公共方法:

XPath

XPath 是一门在 XML 文档中查找信息的路径语言,W3C 文档:XML Path Language (XPath), Version 1.0

所有的查找都是基于参考定位的,依靠两者之间存在的某种关系,或主从,或平级,这样一步一步的查到。

在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。

XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。

下面列出了最有用的路径表达式:

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。

XPath 通配符可用来选取未知的 XML 元素。

通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

通过在路径表达式中使用“|”运算符,可以选取若干个路径,“|”两边的表达式是互相独立的,并非是一个表达式下。

除了上面介绍的还有两个概念需要知道:轴(Axes)谓语

通过以上介绍我们基本可以进行选取节点了,但是有可能选的节点有点多,那么这时候就需要用谓语了。谓语就是用来做过滤的,过滤条件均写在[]中。

这个过滤条件可写内容有很多:运算符表达式、数字、函数以及文字( Literal ,W3C 的英文介绍没仔细看,没太懂 Literal 说的是什么)。

w3school 给的一个例子,比较有代表性吧。

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang='eng'] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

Xpath 的轴定于的是相对于当前节点具有某种相同特征的节点集。

轴名称 结果
ancestor 选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素(子、孙等)。
descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
preceding 选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling 选取当前节点之前的所有同级节点。
self 选取当前节点。

每一个step都是由轴名称::NodeTest[谓语]构成。比如:child::*/child::pricechild::*child::price都是一个step

 

make_file(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])

lxml.html

Since version 2.0, lxml comes with a dedicated Python package for dealing with HTML: lxml.html. It is based on lxml's HTML parser, but provides a special Element API for HTML elements, as well as a number of utilities for common HTML processing tasks.

The main API is based on the lxml.etree API, and thus, on the ElementTree API.

lxml.html 是一个专门用来处理 HTML 文档的,虽然他依旧是基于 HTML parser 的,但是她提供了很多有针对性的 API 。这里只作一个简单介绍,深入了解,请查阅官方文档。

首先在解析 HTML 文本上增加了几个方法:

  • document_fromstring(string)
  • fragment_fromstring(string, create_parent=False)
  • fragments_fromstring(string)

其次对于 HTML 元素,除了之前的方法之外又加了一些:

  • .drop_tree()

    删除该元素及其所有子元素,就像 el.getparent().remove(el),但是不会删除该元素的 .tail ,.tail 将会与前一个元素合并。

  • .drop_tag()

    删除该标签,但是会保留该元素的子元素与文本。

  • .find_class(class_name)

    返回一个含有 class_name CSS 的元素列表。

  • .find_rel_links(rel)

    返回一个<a rel="{rel}">的元素列表

  • .get_element_by_id(id, default=None)

    通过 id 查找元素,如果没有返回默认,假如文档不合规出现多个同 id 的元素,仅返回第一个。

  • .text_content()

    返回元素的文本内容,包括其子代的文本内容。

  • .cssselect(expr)

    通过 CSS 选择器选择元素。

  • .set(key, value=None)

    设置元素属性,如果 value 没有给或者是 None ,那么将创建一个 boolean attribute (属性只要出现即表示真,无论 value 是什么,哪怕是个空串) E.g. <div checked></div>

正如文章开头说的那个, lxml.html.soupparser 可以引入 BeautifulSoup ,甚至可以仅使用 BeautifulSoup 的编码检测模块 UnicodeDammit 。

最后就是可以使用 lxml.html.open_in_browser(lxml_doc) 直接在浏览器中显示文档,甚至可以对文档的表单进行提交操作。

以上都是据自己的理解而写,如有错误之处,欢迎交流。

 

用来生成一个包含表格的html文件,其内容是用来展示差异。

fromlinestolines,用于比较的内容,格式为字符串组成的列表

fromdesctodesc,可选参数,对应的fromlines,tolines的差异化文件的标题,默认为空字符串

contextnumlines,可选参数,context 为True时,只显示差异的上下文,为false,显示全文,numlines默认为5,当context为True时,控制展示上下文的行数,当context为false时,控制不同差异的高亮之间移动时“next”的开始位置(如果设置为0,当移动懂顶端时,超链接会丢失引用地址)

make_table(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])

这个方法和make_file用法一样,唯一的区别在于它只生成了一个html表格字符串

python安装包的Tools/scripts/diff.py是关于他们使用的一个很好的例子,它可以用命令行来运行。

新增于python2.4

difflib.context_diff(a, b[, fromfile][, tofile][, fromfiledate][, tofiledate][, n][, lineterm])

用来比较a,b,a,b都是字符串列表。返回一个格式化文本的差异。

他是一个用来展示少量差异的好方法,这种变化,用前/后的样式进行展示,n默认为3,用来控制展示发现的差异数

默认情况下,差异控制行(*** or ---)用来把a,b的差异区隔开来,便于程序读写处理,如果不需要这样做的话,可以设置lineterm为"",这样,就会卸载一行里

如果格式化差异文本需要标题和修改时间信息,通过fromfile, tofile, fromfiledate, 和 tofiledate进行控制,如果不设置,默认为空

>>> s1 = ['baconn', 'eggsn', 'hamn', 'guidon']
>>> s2 = ['pythonn', 'eggyn', 'hamstern', 'guidon']
>>> for line in context_diff(s1, s2, fromfile='before.py', tofile='after.py'):
...     sys.stdout.write(line)  
*** before.py
--- after.py
***************
*** 1,4 ****
! bacon
! eggs
! ham
  guido
--- 1,4 ----
! python
! eggy
! hamster




guido difflib.get_close_matches

(

word, possibilities[, n][, cutoff]

)

 返回一个最相似匹配的列表word,用来进行匹配的片段(典型的应用是字符串)

possibilities,用来匹配word的片段

n,默认为3,返回的最多结果数,必须大于0

cutoff,默认为0.6,匹配的相似因数,他是一个介于0,1的浮点数
>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])
['apple', 'ape']
>>> import keyword
>>> get_close_matches('wheel', keyword.kwlist)
['while']
>>> get_close_matches('apple', keyword.kwlist)
[]
>>> get_close_matches('accept', keyword.kwlist)
['except']
difflib.ndiff

(

a, b[, linejunk][, charjunk]

)

比较a和b,返回差异

linejunk和charjunk都是用来匹配的方法

linejunk:接收一个字符串的方法,如果这个字符串被认定为垃圾,则返回true,否则为false,默认为None,他调用了IS_LINE_JUNK()这个方法,这个方法存在bug,他不能过滤掉’#’周围的不可见字符,2.3以后,对这个方法进行了动态分析,表现会比以前好些

charjunk:接受一个字符的方法,如果这个字符被认定为垃圾,则返回true,否则为false,它调用了IS_CHARACTER_JUNK(), 他会自动过滤掉空白字符(所以,不要用空白字符或者制表符作为分隔符)

Tools/scripts/ndiff.py 是执行这一方法的实例:

>>> diff = ndiff('onentwonthreen'.splitlines(1),
...              'orentreenemun'.splitlines(1))
>>> print ''.join(diff),
- one
?  ^
  ore
?  ^
- two
- three
?  -
  tree
  emu
difflib.restore

(

sequence, which

)

返回1或2的差异对Differ.compare() 或者 ndiff()的结果进行处理,根据参数which,返回片段1或者片段2的差异化结果实例:

>>> diff = ndiff('onentwonthreen'.splitlines(1),
...              'orentreenemun'.splitlines(1))
>>> diff = list(diff) # materialize the generated delta into a list
>>> print ''.join(restore(diff, 1)),
one
two
three
>>> print ''.join(restore(diff, 2)),
ore
tree
emu

difflib.``unified_diff(a, b[, fromfile][, tofile][, fromfiledate][, tofiledate][, n][, lineterm])

用来比较a,b,a,b都是字符串列表。返回一个统一的格式化文本的差异。

使用方式和difflib.context_diff一样,只是返回的内容展示格式有差异

>>> s1 = ['baconn', 'eggsn', 'hamn', 'guidon']
>>> s2 = ['pythonn', 'eggyn', 'hamstern', 'guidon']
>>> for line in unified_diff(s1, s2, fromfile='before.py', tofile='after.py'):
...     sys.stdout.write(line)   
--- before.py
    after.py
@@ -1,4  1,4 @@
-bacon
-eggs
-ham
 python
 eggy
 hamster
 guido

 

 

difflib.``IS_LINE_JUNK(line)如果是需要忽略的行,则返回为true,如果这个行内全为空格或者只有’#’,则将这行忽略掉

`difflib.IS_CHARACTER_JUNK(*ch*)如果是需要忽略的字符,则返回为true,如果这个字符为空格,则将这行忽略掉`

-帮助进行差异化比较 这个模块提供的类和方法用来进行差异化比较,它能够生成文本或者html格式的差异化比较结果,如果需要比较...

版权声明:本文由可提现彩票app-支持提现彩票app-10元可提现的彩票app发布于可提现彩票app,转载请注明出处:学习笔记,复杂的xml文件对比