使用 groovy 更新 xml 文件时保留格式 [英] preserve formatting when updating xml file with groovy

查看:9
本文介绍了使用 groovy 更新 xml 文件时保留格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有大量包含 URL 的 XML 文件.我正在编写一个 groovy 实用程序来查找每个 URL 并将其替换为更新版本.

I have a large number of XML files that contain URLs. I'm writing a groovy utility to find each URL and replace it with an updated version.

给定example.xml:

Given 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&amp;escaped=true
                </url>
            </link>
        </section>
    </content>
</page>

脚本运行后,example.xml 应包含:

Once the script has run, example.xml should contain:

<?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&amp;stillEscaped=true
                </url>
            </link>
        </section>
    </content>
</page>

使用 groovy 出色的 xml 支持很容易做到这一点,除了我想更改 URL 而没有其他内容关于文件.

This is easy to do using groovy's excellent xml support, except that I want to change the URLs and nothing else about the file.

我的意思是:

  • 空格不得更改(文件可能包含空格、制表符或两者)
  • 必须保留评论
  • 必须保留 windows 与 unix 样式的行分隔符
  • 不得添加或删除顶部的 xml 声明
  • 标签中的属性必须保持其顺序

到目前为止,在尝试了 XmlParser、DOMBuilder、XmlNodePrinter、XmlUtil.serialize() 等的多种组合之后,我已经开始逐行读取每个文件并应用 xml 实用程序和正则表达式.

So far, after trying many combinations of XmlParser, DOMBuilder, XmlNodePrinter, XmlUtil.serialize(), and so on, I've landed on reading each file line-by-line and applying an ugly hybrid of the xml utilities and regular expressions.

读取和写入每个文件:

files.each { File file ->
    def lineEnding = file.text.contains('
') ? '
' : '
'
    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)
        }
    }
}

在一行中搜索和更新 URL:

Searching for and updating URLs within a line:

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(/[
]/, '')
}

这主要是有效的,除了它不能处理分成多行的标签,并且在写回文件时弄乱换行符很麻烦.

This mostly works, except it can't handle a tag split over multiple lines, and messing with newlines when writing the files back out is cumbersome.

我是 groovy 的新手,但我觉得必须有一种更好的方法来做到这一点.

I'm new to groovy, but I feel like there must be a groovier way of doing this.

推荐答案

我刚刚创建了要点:https://gist.github.com/akhikhl/8070808 演示如何使用 Groovy 和 JDOM2 完成此类转换.

I just created gist at: https://gist.github.com/akhikhl/8070808 to demonstrate how such transformation is done with Groovy and JDOM2.

重要说明:

  1. Groovy 在技术上允许使用任何 Java 库.如果有什么不能用 Groovy JDK 来完成,它可以用其他库来完成.
  2. jaxen 库(实现 XPath)应明确包含(通过 @Grab 或通过 maven/gradle),因为它是 JDOM2 的可选依赖项.
  3. @Grab/@GrabExclude 指令序列修复了 jaxen 对 JDOM-1.0 的古怪依赖.
  4. XPathFactory.compile 还支持变量绑定和过滤器(参见在线 javadoc).
  5. XPathExpression(由 compile 返回)支持两个主要函数 - 评估和评估第一.评估始终返回满足指定谓词的所有 XML 节点的列表,而评估第一只返回第一个匹配的 XML 节点.

更新

以下代码:

new XMLOutputter().with {
  format = Format.getRawFormat()
  format.setLineSeparator(LineSeparator.NONE)
  output(doc, System.out)
}

解决了保留空格和行分隔符的问题.getRawFormat 构造一个保留空格的格式对象.LineSeparator.NONE 指示格式对象,它不应该转换行分隔符.

solves a problem with preserving whitespaces and line separators. getRawFormat constructs a format object that preserves whitespaces. LineSeparator.NONE instructs format object, that it should not convert line separators.

上面提到的要点也包含这个新代码.

The gist mentioned above contains this new code as well.

这篇关于使用 groovy 更新 xml 文件时保留格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆