YAML XML过滤器

时间:2018-05-01 01:54:21

标签: xml groovy yaml

我想做以下事情:

我想使用YAML文件来定义要在XML文件中更改的值。从理论上讲,这是在天堂进行的比赛,但细节如何运作。下面的代码在几个级别上是错误的,但它显示了我需要的内容。事情是没有办法按叶子走YAML文件,我在这里需要。因此,我需要采用一些令人讨厌的递归方法去除"路径"。

第二个问题是,即使我有一个表格中的路径" parent1 [0] .parent2 [0]。@ description"我不能去xmlIn。" $ {pathVariable}" =值因为这只适用于直接孩子。

#!/usr/bin/env groovy

// Test for YAML

import groovy.util.* 
import groovy.text.*
import groovy.xml.*
@Grab('org.yaml:snakeyaml:1.18')

// YAML file
def yamlFile = '''"@description": "testParent1"

parent1[0]:
   parent2[0]:
      "@description": "testParent2"

'''

def xmlFile = '''
<root>
   <parent1 description="test0">
     <parent2 description="test1" />
   </parent1>
   <parent1>
      <parent2 description="test2" />
   </parent1>
</root>
'''


def config = new org.yaml.snakeyaml.Yaml().load(yamlFile)

def xmlIn = new XmlParser().parseText(xmlFile)

config.each {
   println "${it.key} = ${it.value}"
   xmlIn."${it.key}" = it.value
}

1 个答案:

答案 0 :(得分:0)

  

事情是没有办法按叶子走YAML文件,我需要在这里。

从技术上讲,没有叶子,因为YAML代表图形,而不是树。它可能有循环因为锚和&amp;别名。但是,您当然可以实现一个自己访问每个节点的walker,只要您集成一个检测周期的检查,这样就不会遇到无限循环。

但我认为这里更直接的策略是走路事件流。这是一种用Java编写的方法(原谅我,我不知道Groovy;但我认为翻译很简单):

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();

List<String> pathComponents = new ArrayList<String>();
int pos = -1; // root event will be MappingStartEvent, which will lift this to 0.
for (Event e: new Yaml().parse(yamlFile)) {
    if (e instanceof MappingStartEvent) {
        if (pos == pathComponents.size()) {
            throw RuntimeException("Mapping as key not supported!");
        }
        pos++;
    } else if (e instanceof MappingEndEvent) {
        pos--;
        // pop recent key from list
        if (pos >= 0) {
            pathComponents.remove(pos);
        }
    } else if (e instanceof ScalarEvent) {
        if (pos == pathComponents.size()) {
            // this is a key, add it to the path
            pathComponents.add(((ScalarEvent) e).value);
        } else {
            // this is a replacement value, do the replacement.
            // last given key must specify an attribute.
            String lastKey = pathComponents.get(pathComponents.size() - 1);
            if (lastKey.charAt(0) != '@') {
                throw RuntimeException("can only change attributes!");
            }
            // attribute name not part of path; pop it
            pathComponents.remove(pos);

            Element userElement = (Element) xpath.evaluate("/" + String.join("/", pathComponents), doc,
            XPathConstants.NODE);
            userElement.setAttribute(lastKey.substring(1), ((ScalarEvent) e).value);
        }
    } else if (e instanceof SequenceStartEvent or e instanceof SequenceEndEvent) {
        throw RuntimeException("sequences not allowed!");
    } else if (e instanceof AliasEvent) {
        throw RuntimeException("aliases not allowed!");
    } else {
        // I skip checking for proper DocumentStartEvent / DocumentEndEvent here
    }
}

此代码未经测试!

有一个名为XModifier的Java库,它看起来更容易修改,但我不知道,它似乎并不普遍,所以要小心。