我有大量包含网址的XML文件。我正在编写一个groovy实用程序来查找每个URL并将其替换为更新版本。
给出example.xml:
<?xml version="1.0" encoding="UTF-8"?>
<page>
<content>
<section>
<link>
<url>/some/old/url</url>
</link>
<link>
<url>/some/old/url</url>
</link>
</section>
<section>
<link>
<url>
/a/different/old/url?with=specialChars&escaped=true
</url>
</link>
</section>
</content>
</page>
脚本运行后,example.xml应包含:
<?xml version="1.0" encoding="UTF-8"?>
<page>
<content>
<section>
<link>
<url>/a/new/and/improved/url</url>
</link>
<link>
<url>/a/new/and/improved/url</url>
</link>
</section>
<section>
<link>
<url>
/a/different/new/and/improved/url?with=specialChars&stillEscaped=true
</url>
</link>
</section>
</content>
</page>
使用groovy优秀的xml支持很容易做到这一点,除了我想更改URL以及其他任何关于文件。
我的意思是:
到目前为止,在尝试了XmlParser,DOMBuilder,XmlNodePrinter,XmlUtil.serialize()等许多组合之后,我已经逐行阅读每个文件,并应用了一个丑陋的xml实用程序和正则表达式。
读取和写入每个文件:
files.each { File file ->
def lineEnding = file.text.contains('\r\n') ? '\r\n' : '\n'
def newLineAtEof = file.text.endsWith(lineEnding)
def lines = file.readLines()
file.withWriter { w ->
lines.eachWithIndex { line, index ->
line = update(line)
w.write(line)
if (index < lines.size-1) w.write(lineEnding)
else if (newLineAtEof) w.write(lineEnding)
}
}
}
搜索和更新一行中的网址:
def matcher = (line =~ urlTagRegexp) //matches a <url> element and its contents
matcher.each { groups ->
def urlNode = new XmlParser().parseText(line)
def url = urlNode.text()
def newUrl = translate(url)
if (newUrl) {
urlNode.value = newUrl
def replacement = nodeToString(urlNode)
line = matcher.replaceAll(replacement)
}
}
def nodeToString(node) {
def writer = new StringWriter()
writer.withPrintWriter { printWriter ->
def printer = new XmlNodePrinter(printWriter)
printer.preserveWhitespace = true
printer.print(node)
}
writer.toString().replaceAll(/[\r\n]/, '')
}
这主要是有效的,除了它无法处理多行分割的标签,并且在将文件写回时弄乱换行很麻烦。
我是groovy的新手,但我觉得必须有更加时髦的方式来做这件事。
答案 0 :(得分:10)
我刚刚在https://gist.github.com/akhikhl/8070808创建了gist,以演示如何使用Groovy和JDOM2完成此类转换。
重要说明:
<强>更新强>
以下代码:
new XMLOutputter().with {
format = Format.getRawFormat()
format.setLineSeparator(LineSeparator.NONE)
output(doc, System.out)
}
解决了保留空格和行分隔符的问题。 getRawFormat构造一个保留空格的格式对象。 LineSeparator.NONE指示格式对象,它不应该转换行分隔符。
上面提到的要点也包含这个新代码。
答案 1 :(得分:7)
有一个没有任何第三方库的解决方案。
def xml = file.text
def document = groovy.xml.DOMBuilder.parse(new StringReader(xml))
def root = document.documentElement
use(groovy.xml.dom.DOMCategory) {
// manipulate the XML here, i.e. root.someElement?.each { it.value = 'new value'}
}
def result = groovy.xml.dom.DOMUtil.serialize(root)
file.withWriter { w ->
w.write(result)
}