我有数百个包含以下文本类型的xml文件
Exception Domains
其中 max_value 元素可能具有不同的值。
问题:我需要在所有文件中将max_value元素的值替换为100(例如)。我尝试过像下面这样的事情。
<Init dflt_value='1.00' max_value='1000000.00' diff_ele='1.0' new='Yes' />
但没有什么对我有用。 它可能是什么解决方案?
答案 0 :(得分:1)
不要使用正则表达式解析XML / HTML,使用正确的XML / HTML解析器和强大的xpath查询。
根据编译理论,无法使用基于finite state machine的正则表达式解析XML / HTML。由于XML / HTML的层次结构,您需要使用pushdown automaton并使用LALR等工具操作YACC语法。
您可以使用以下其中一项:
xmllint通常默认使用libxml2
,xpath1安装(检查my wrapper以使换行符分隔输出
xmlstarlet可以编辑,选择,转换......默认情况下不安装,xpath1
通过perl的模块XML :: XPath,xpath1 安装xidel xpath3
saxon-lint我自己的项目,包装在@Michael Kay的Saxon-HE Java库中,xpath3
python的lxml
(from lxml import etree
)
perl的XML::LibXML
,XML::XPath
,XML::Twig::XPath
,HTML::TreeBuilder::XPath
ruby nokogiri,check this example
php DOMXpath
,check this example
检查:Using regular expressions with HTML tags
xmlstarlet ed -u '//Init/@max_value' -v '100' *.xml
如果您要编辑 ,请使用-L
开关:
xmlstarlet ed -L -u '//Init/@max_value' -v '100' *.xml
# edit in place XML
from lxml import etree
import sys
myXML = sys.argv[1]
tree = etree.parse(myXML)
root = tree.getroot()
code = root.xpath("//Init")
for i in code:
if (i.attrib['max_value']):
i.attrib['max_value'] = '100'
etree.ElementTree(root).write(myXML, pretty_print=True)
答案 1 :(得分:1)
你的具体问题是,在sed中,.*
是“贪婪的”。也就是说,它尽可能地匹配 ,这可能导致它将两个或多个字段合并为一个。
你想要对你的比赛更加小心。要替换数字,请尝试只匹配数字,可能是小数点:
s/max_value='[0-9.]*'/max_value='25'/g
通常,您要做的是使用结束引号的否定字符类:
s/'[^']*'/ ...
但是在这个特定的情况下,0-9完成了这项工作,并且稍微清楚一些。 (您不希望尝试使用这种方式使用正模式匹配句子中的每个可能字符 - 使用负模式更好,只说“除了结束引号之外的所有内容,然后是结束引用”。
答案 2 :(得分:1)
问题是您在'
subexpr中包含.*
个字符。更好用:
xargs sed "/max_value=/s/max_value='[^']*'/max_value='${new_value}'/g"
请注意'
是shell的特殊字符(所以我在整个sed命令周围使用双引号)
还要考虑到表达式不仅可以出现在您正在搜索的位置。由于XML不是常规的,因此用匹配的正则表达式解析它并不是一个好主意。使用完整的XML解析器将允许您以xml属性为基础更改所有实例,而不是纯文本搜索。并且考虑到grep(1)
是一个过滤器,您不会编辑文件,您将在标准输出上获得该文件。
如果要编辑文件,可以使用ed(1)
代替。
grep -rl max_value . |
while read file
do
ed file <<EOF
1,$s/max_value='[^']'/max_value='100'/g
w
q
EOF
done