今天介绍一个如何通过Dom4J的Visitor模式替换XML文件中正则表达式的方法,感兴趣的话可以看看。
Vistor模式不是本文关注的重点,感兴趣可以看一下本文:http://www.patterndepot.com/put/8/visitor.pdf
Dom4J提供了一个接收Vistor的接口,可以通过自定义Vistor实现类对XML文件中的正则表达式进行替换,原理很简单,就不在此赘述了,直接上例子吧。
首先是XML配置文件: deployment.xml
<deployment id="${deploy.id}"> <build> <release>${build.release}</release> <type>${build.type}</type> <number>${build.number}</number> </build> <host> <id>${deploy.host}</id> <localdir>#{deploy.host:LocalHome}</localdir> <user>#{deploy.host:User}</user> <password>#{deploy.host:Password}</password> </host> </deployment>
然后是XMLVariableTransformer,这个类是我自定义的一个类,用来封装替换正则表示的一些方法。
package com.javaeye.terrencexu.dom4j; import java.io.ByteArrayInputStream; import java.io.File; import java.util.Map; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.VisitorSupport; import org.dom4j.io.SAXReader; public class XMLVariableTransformer { private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{([\\w\\d\\./_]+)}"); private static final Pattern HOST_VARIABLE_PATTERN = Pattern.compile("#\\{([\\w\\d\\./_]+):([\\w\\d\\./_]+)}"); private Properties config; private Map<String, Properties> hostConfigs; public XMLVariableTransformer(Properties config, Map<String, Properties> hostConfigs) { this.config = config; this.hostConfigs = hostConfigs; } public String transform(String xml) { SAXReader reader = new SAXReader(); try { Document doc = reader.read(new ByteArrayInputStream(xml.getBytes())); doc.accept(new VariableVistor()); return doc.asXML(); } catch (DocumentException e) { e.printStackTrace(); throw new RuntimeException("Unable to read xml data", e); } } public String transform(File xml) { SAXReader reader = new SAXReader(); try { Document doc = reader.read(xml); doc.accept(new VariableVistor()); return doc.asXML(); } catch (DocumentException e) { e.printStackTrace(); throw new RuntimeException("Unable to read xml data", e); } } private class VariableVistor extends VisitorSupport { public void visit(Attribute attr) { parseNode(attr); } public void visit(Element node) { parseNode(node); } private void parseNode(Node node) { String substitution = getSubstitution(node.getText()); if(substitution != null) { node.setText(substitution); } } private String getSubstitution(String expression) { Matcher m = XMLVariableTransformer.VARIABLE_PATTERN.matcher(expression); if(m.matches()) { return config.getProperty(m.group(1)); } m = XMLVariableTransformer.HOST_VARIABLE_PATTERN.matcher(expression); if(m.matches()) { String host = config.getProperty(m.group(1)); return hostConfigs.get(host).getProperty(m.group(2)); } return null; } } }
该类中的内嵌类VariableVisitor继承了接口Visitor的默认实现类VisitorSupport,通过该类可以在遍历deployment.xml的每个节点以及attribute的时候按规则替换正则表达式。
最后是一个测试
package com.javaeye.terrencexu.dom4j; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; public class Test { public static void main(String[] args) throws IOException { Properties config = new Properties(); config.setProperty("deploy.id", "test"); config.setProperty("build.release", "release1"); config.setProperty("build.type", "type1"); config.setProperty("build.number", "latest"); config.setProperty("deploy.host", "localhost"); Map<String, Properties> hostConfigs = new HashMap<String, Properties>(); Properties hostConfig = new Properties(); hostConfig.setProperty("LocalHome", "c:\\install\\"); hostConfig.setProperty("User", "Administrator"); hostConfig.setProperty("Password", "abc123_"); hostConfigs.put("localhost", hostConfig); File xmlFile = new File("C:\\eclipse\\workspace1\\Terrence-JavaStudy\\study-dom4j\\conf\\deployment.xml"); String xml = FileUtils.readFileToString(xmlFile); XMLVariableTransformer tranformer = new XMLVariableTransformer(config, hostConfigs); String deployment = tranformer.transform(xml); System.out.println(deployment); } }
运行结果如下:
<?xml version="1.0" encoding="UTF-8"?> <deployment id="test"> <build> <release>release1</release> <type>type1</type> <number>latest</number> </build> <host> <id>localhost</id> <localdir>c:\install\</localdir> <user>Administrator</user> <password>abc123_</password> </host> </deployment>
-- Done --