上下文:
我继承了一个包含2.5个MLOC的旧版应用程序,该MLOC分布在大约2,000个文件中(当前PHP 5.5.9,jQuery,HTML)。在此代码库中,有许多安全漏洞,代码气味和性能问题。我的任务是改善信息安全,并将此代码库带入21世纪。我正在使用Python进行这些批量编辑。
问题:
我需要编辑每个文件并修改代码。我已经通过基本的字符串比较解决了单行编辑问题。
这是典型的脚本结构:
<?php
// some code here
?>
<html><head>
...
</head>
<body>
...
</body>
<script>
...
</script>
</html>
现在,我需要开始修改HTML的整个块,使用混合引号(单行和双引号)的内联javascript,并从脚本中删除方法。
例如,我有一个HTML的开头部分,如下所示:
<head>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<script type="text/javascript" src="jquery.form.js"></script>
<title>TITLE</title>
<!-- TemplateIB -->
<link rel="Stylesheet" href="../Lib/jquery-ui-1.10.3.custom.min.css" />
<link rel="Stylesheet" href="../Lib/3CLStyle.css" />
<script language="JavaScript" type="text/javascript" src="../Lib/jquery-1.9.1-Combined.min.js"></script>
<link rel="stylesheet" type="text/css" href="../Lib/jquery.datetimepicker.css" />
<script src="../Lib/jquery.datetimepicker.full.js"></script>
</head>
我需要将其修改为:
<head>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<title>TITLE</title>
<!-- Stylesheets -->
<link rel="stylesheet" href="../Lib/jquery-ui-1.10.3.custom.min.css" />
<link rel="stylesheet" type="text/css" href="../Lib/jquery.datetimepicker.css" />
<link rel="stylesheet" href="../Lib/3CLStyle.css" />
<!-- Boilerplate JS -->
<script type="text/javascript" src="../Lib/jquery-1.9.1-Combined.min.js"></script>
<script type="text/javascript" src="jquery.form.js"></script>
<script type="text/javascript" src="../Lib/jquery.datetimepicker.full.js"></script>
<!-- Custom JS -->
<script type="text/javascript" src="../js/contactHistory.js"></script>
</head>
这里最大的障碍是,换行符并不是都统一的-该代码库已有十多年的历史,并且有很多人在摸索它。因此不存在统一性。例如,某些文件如下所示:
<head><meta http-equiv="X-UA-Compatible" content="IE=9" />
<title>
...
其他类似上面的示例。一些使用制表符缩进,另一些使用空格。空白的应用方式有很多差异。
我看到的另一个障碍的另一个例子是这样的情况:
<input type="button" class="submit" value="Check History" onclick="CreateHistoryTable()" />
我需要将其修改为:
<input type="button" class="submit" value="Check History" onclick="createHistoryTable(' <?= $_GET['phone'] ? $_GET['phone'] : ''; ?>', '<?= $_GET['project'] ? $_GET['project'] : ''; ?>' )" />
潜在的解决方案:
就像我说的那样,我已经有效地解决了单行编辑问题。对于这些更复杂的场景,我已经考虑过RegEx,但这给本来就很困难的情况又增加了另一层复杂性。
根据我的阅读,看来Beautiful Soup可能满足我的需求。有人可以建议吗?元素树也是另一种选择,我只是没有深入研究这两种选择,以了解它们是否会促进我需要做的重组和深度编辑。
现在,解决空格问题的一种方法是美化HTML,并使其统一。看来lxml有一个基于Beautiful Soup的很好的实现,它并不关心白间距。
下一步是块编辑-这确实是目前最大的障碍。 lxml可能是实现此目的的关键,但是我很少能找到能实现我所要实现的示例代码。
我不是在寻找任何人来编写代码,我只是在寻找有关如何处理这些更复杂案例的输入。谢谢您的协助。
答案 0 :(得分:1)
首先,不要编写一个一次性完成所有任务的大型脚本。编写许多较小的脚本来修复一些问题。较小的将更易于编码,调试和维护。
这是使用BeautifulSoup的方法。
from bs4 import BeautifulSoup, Comment, NavigableString
from collections import defaultdict
html = '''
<head>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<script type="text/javascript" src="jquery.form.js"></script>
<script type="text/javascript" src="../js/contactHistory.js"></script>
<title>TITLE</title>
<!-- TemplateIB -->
<link rel="Stylesheet" href="../Lib/jquery-ui-1.10.3.custom.min.css" />
<link rel="Stylesheet" href="../Lib/3CLStyle.css" />
<script language="JavaScript" type="text/javascript" src="../Lib/jquery-1.9.1-Combined.min.js"></script>
<link rel="stylesheet" type="text/css" href="../Lib/jquery.datetimepicker.css" />
<script src="../Lib/jquery.datetimepicker.full.js"></script>
</head>
'''
soup = BeautifulSoup(html)
# some way to distinguish the js libraries
boilerplate_js = [
"../Lib/jquery-1.9.1-Combined.min.js",
"jquery.form.js",
"../Lib/jquery.datetimepicker.full.js"
]
tags = defaultdict(list)
# extract all the tags in the <head>...</head> element and
# put them under various keys in the tags dictionary
for tag in list(soup.html.head):
if tag.name is not None:
tag = tag.extract()
# differentiate 'custom' scripts from 'boilerplate'
if tag.name == 'script' and tag['src'] not in boilerplate_js:
tags['custom_js'].append(tag)
else:
tags[tag.name].append(tag)
# comments (and some other things) don't have tag names
elif isinstance(tag, Comment):
tags['Comment'].append(tag)
# elif .... ignoring other possible tags
#create a new <head>...</head> element to be populated below
new_head = soup.new_tag('head')
# for each kind of tag in the tags dictionary
# we append them to the new_head element
# appending '\n's and ' 's is just for formatting
#obviously, this can be refactored alot
if 'meta' in tags:
for tag in tags.pop('meta'):
new_head.append('\n ')
new_head.append(tag)
if 'title' in tags:
new_head.append('\n ')
for tag in tags.pop('title'):
new_head.append('\n ')
new_head.append(tag)
if 'link' in tags:
new_head.append('\n\n ')
new_head.append(Comment(' Stylesheets '))
for tag in tags.pop('link'):
new_head.append('\n ')
new_head.append(tag)
if 'script' in tags:
new_head.append('\n\n ')
new_head.append(Comment(' Boilerplate JS '))
for tag in tags.pop('script'):
new_head.append('\n ')
new_head.append(tag)
if 'custom_js' in tags:
new_head.append('\n\n ')
new_head.append(Comment(' Custom JS '))
for tag in tags.pop('custom_js'):
new_head.append('\n ')
new_head.append(tag)
if len(tags):
new_head.append('\n\n ')
new_head.append(Comment(' Other stuff '))
for key in list(tags.keys()):
for tag in tags.pop(key):
new_head.append('\n ')
new_head.append(tag)
new_head.append('\n')
soup.html.head.replace_with(new_head)
print(soup)
输出:
<html><head>
<meta content="IE=9" http-equiv="X-UA-Compatible"/>
<title>TITLE</title>
<!-- Stylesheets -->
<link href="../Lib/jquery-ui-1.10.3.custom.min.css" rel="Stylesheet"/>
<link href="../Lib/3CLStyle.css" rel="Stylesheet"/>
<link href="../Lib/jquery.datetimepicker.css" rel="stylesheet" type="text/css"/>
<!-- Boilerplate JS -->
<script src="jquery.form.js" type="text/javascript"></script>
<script language="JavaScript" src="../Lib/jquery-1.9.1-Combined.min.js" type="text/javascript"></script>
<script src="../Lib/jquery.datetimepicker.full.js"></script>
<!-- Custom JS -->
<script src="../js/contactHistory.js" type="text/javascript"></script>
<!-- Other stuff -->
<!-- TemplateIB -->
</head>
</html>