今天介绍一个如何通过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 --