XML文件解析
在现在很多采用java开发的基于b\s结构的系统中,经常将一些配置参加放到一个xml文件中,然后在这个文件中取参数,这样减少了hard code的情况。下面这个类就是用来解析xml文件的。具体使用参考main方法的的写法。
/**
* filename: XMLProcess.java
* description: XML文件解析
* date: 2004-12-07
* @author sunlen
*
* History: // 历史修改记录
* <author> <time> <version > <desc>
*/
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import java.net.*;
public class XMLProcess
{
/** XML解析器工厂。*/
private static DocumentBuilderFactory factory;
/** XML解析器。*/
private static DocumentBuilder builder;
/** XML头。*/
private static final String XML_HEAD = "<?xml version=\"1.0\" encoding=\"gb2312\"?>";
/** 缩进前缀。*/
private static String indent = " ";
/** 该配置内存中数据是否与配置文件内容一致,不一致则为脏。*/
private boolean isDirty;
/** 代表该配置文件的文档类。*/
private Document doc;
/** 配置根节点。*/
private Element root;
/** 配置文件名。*/
private String file;
/**
* 创建配置读取对象。
* @param url 保存配置信息的XML文件路径。
*/
public XMLProcess(String url) throws IOException
{
this(url,false);
}
/**
* 创建配置读取对象。
* @param url 保存配置信息的XML文件路径。
* @param create 当配置文件不存在时,是否允许新建文件。
* @throws IOException 配置文件访问或内容解析异常。
*/
public XMLProcess(String url, boolean create) throws IOException
{
//得到配置信息
if (url==null)
{
throw new IllegalArgumentException("url is null");
}
if (url.indexOf(':')>1)
{
this.file = url;
}
else
{
this.file = new File(url).toURL().toString();
}
//为了检查参数file的合法性,如传的参数不合法,则抛出异常,调用者对其进行出错处理
new URL(this.file); //创建文件对象
try
{
load(); //读取配置文件
}
catch (FileNotFoundException ex)
{
if(!create)
{ //文件不存在,且不允许新建
throw ex;
}
else
{ //文件不存在,但允许新建
loadXMLParser(); //加载XML解析器
doc = builder.newDocument(); //创建空文档对象
root = doc.createElement("config");
doc.appendChild(root); //增加根节点
isDirty = true;
flush(); //保存到文件
return;
}
}
}
/**
* 输出缩进空格。
* @param pw 输出目的地。
* @param level 缩进深度。
*/
private static void writeIndent(PrintWriter pw,int level)
{
for (int i=0;i<level;i++)
{
pw.print(indent);
}
}
/**
* 以XML格式递归输出一个节点。
* @param node 输出起始节点。
* @param pw 输出目的地。
* @param 递归调用的深度标记,请输入0。
*/
private static void writeNode(Node node, PrintWriter pw, int deep)
{
switch (node.getNodeType())
{
case Node.COMMENT_NODE: //注释节点
writeIndent(pw,deep);
pw.print("<!--");
pw.print(node.getNodevalue());
pw.println("-->");
return;
case Node.TEXT_NODE: //文本节点
String value = node.getNodevalue().trim(); //文本trim防止破坏缩进格式
if (value.length()==0)
{
return;
}
writeIndent(pw,deep);
for (int i=0;i<value.length();i++)
{
char c = value.charAt(i);
switch(c)
{
case '<':
pw.print("<");
break;
case '>':
pw.print("<");
break;
case '&':
pw.print("&");
break;
case '\'':
pw.print("'");
break;
case '\"':
pw.print(""");
break;
default:
pw.print(c);
}
}
pw.println();
return;
case Node.ELEMENT_NODE: //标记节点
if (!node.hasChildNodes())
{
return;
}
for (int i=0;i<deep;i++)
{
pw.print(indent);
}
String nodeName = node.getNodeName();
pw.print('<');
pw.print(nodeName);
//输出属性
NamedNodeMap nnm = node.getAttributes();
if (nnm!=null)
{
for (int i=0; i<nnm.getLength(); i++)
{
Node attr = nnm.item(i);
pw.print(' ');
pw.print(attr.getNodeName());
pw.print("=\"");
pw.print(attr.getNodevalue());
pw.print('\"');
}
}
//输出子节点
if (node.hasChildNodes())
{
NodeList children = node.getChildNodes();
if (children.getLength()==0)
{
pw.print('<');
pw.print(nodeName);
pw.println("/>");
return;
}
if (children.getLength()==1)
{
Node n = children.item(0);
if(n.getNodeType()==Node.TEXT_NODE)
{
String v = n.getNodevalue();
if (v!=null)
{
v = v.trim();
}
if (v==null||v.length()==0)
{
pw.println(" />");
return;
}
else
{
pw.print('>');
pw.print(v);
pw.print("</");
pw.print(nodeName);
pw.println('>');
return;
}
}
}
pw.println(">");
for (int i=0;i<children.getLength();i++)
{
writeNode(children.item(i),pw,deep+1);
}
for (int i=0;i<deep;i++)
{
pw.print(indent);
}
pw.print("</");
pw.print(nodeName);
pw.println(">");
}
else
{
pw.println("/>");
}
return;
case Node.DOCUMENT_NODE: //文档节点
pw.println(XML_HEAD);
NodeList nl= node.getChildNodes();
for (int i=0;i<nl.getLength();i++)
{
writeNode(nl.item(i),pw,0);
}
return;
}
}
/**
* 根据key指定的关键字查找节点,在查找的过程中顺便将不存在的节点创建出来。
* @param key 所查找节点的关键字。
* @return 返回查到的节点,没查到则返回null。
*/
public Node findNode(String key)
{
Node ancestor = root;
for (StringTokenizer st = new StringTokenizer(key,"/");
st.hasMoreTokens();)
{
String nodeName = st.nextToken();
NodeList nl = ancestor.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{
Node n = nl.item(i);
if (nodeName.equals(n.getNodeName()))
{
ancestor = n;
//到达key的最低一级了
if (!st.hasMoreTokens())
{
return n;
}
break;
}
}
}
return null;
}
/**
* 根据key指定的关键字创建节点,将会把key代表的整个路径上的节点都创建出来。
* @param key 所查找节点的关键字。
* @return 返回最底层节点,即使已经存在,没有创建新节点。
*/
private Node createNode(String key)
{
Node ancestor = root;
token:
for (StringTokenizer st = new StringTokenizer(key,"/");
st.hasMoreTokens();)
{
String nodeName = st.nextToken();
NodeList nl = ancestor.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{
Node n = nl.item(i);
//该级子节点存在则继续找下一级子节点
if (nodeName.equals(n.getNodeName()))
{
ancestor = n;
if (st.hasMoreTokens())
{
continue token;
}
else
{
return ancestor;
}
}
}
//该级子节点不存在
for(;;) //死循环
{
Node n = doc.createElement(nodeName);
ancestor.appendChild(n);
ancestor = n;
if(!st.hasMoreTokens())
{
return ancestor;
}
nodeName = st.nextToken();
}
}
return null; //不可能执行到这里
}
/**
* 根据key指定的关键字查找节点,在查找的过程中顺便将不存在的节点创建出来。
* @param ancestor 以该节点为祖先开始查找。
* @param key 所查找节点的关键字。
* @return 返回查到的节点,没查到则返回null。
*/
private Node createNode(Node ancestor, String key)
{
searchToken: //用来跳出两层循环用的标记
for (StringTokenizer st = new StringTokenizer(key,"/");
st.hasMoreTokens();)
{
String nodeName = st.nextToken();
NodeList nl = ancestor.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{
if (nodeName.equals(nl.item(i).getNodeName()))
{
ancestor = nl.item(i);
continue searchToken;
}
}
return null;
}
return ancestor;
}
/**
* 取名字为key的节点的值。如果该节点存在,但无内容则返回空字符串:""
* @param key 和该关键字关联的配置项的值将被返回。
* @param def 若key对应的配置项不存在,则返回该值。
* @exception NullPointerException key值为null。
*/
public String get(String key, String def)
{
if (key == null)
{
throw new NullPointerException("parameter key is null");
}
Node node = findNode(key);
if (node==null) //节点不存在返回空
{
return def;
}
NodeList nl = node.getChildNodes();
for (int i=0;i<nl.getLength();i++)
{
if (nl.item(i).getNodeType()==Node.TEXT_NODE)
{
return nl.item(i).getNodevalue().trim();
}
}
node.appendChild(doc.createTextNode(def));
return def;
}
/**
* 设名字为key的节点的值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
* @exception NullPointerException 传入的key或value为null。
*/
public void put(String key, String value)
{
if (key == null)
{
throw new NullPointerException("parameter key is null");
}
if (value == null)
{
throw new NullPointerException("parameter value is null");
}
value = value.trim();
Node node = createNode(key);
//node节点的第一个文本子节点(不包括trim后为空的)放置该节点的值
NodeList nl = node.getChildNodes();
for (int i=0;i<nl.getLength();i++)
{
Node child = nl.item(i);
if (child.getNodeType()==Node.TEXT_NODE) //遇到第一个文本子节点
{
String childvalue = child.getNodevalue();
if (childvalue==null)
{
continue;
}
childvalue = childvalue.trim();
if (childvalue.length()==0)
{
continue;
}
//put的值和原来一样,直接返回即可
if (childvalue.equals(value))
{
return;
}
else
{
child.setNodevalue(value);
isDirty = true;
return;
}
}
}
//没有trim后还有内容的文本子节点
if (nl.getLength()==0) //节点为空
{
node.appendChild(doc.createTextNode(value));
}
else //节点非空
{
Node f = node.getFirstChild();
if (f.getNodeType()==Node.TEXT_NODE)
{
f.setNodevalue(value);
}
else
{
node.insertBefore(doc.createTextNode(value),f);
}
}
isDirty = true; //修改后,脏标记设为真
}
/**
* 取名字为key的节点的布尔值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public boolean getBoolean(String key, boolean def)
{
String str = String.valueOf(def); //把布尔型def变成字符串类str
boolean result;
String resstr = get(key,str);
Boolean resboolean = Boolean.valueOf(resstr);
result = resboolean.booleanvalue();
return result;
}
/**
* 取名字为key的节点的整型值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public int getInt(String key,int def)
{
int result;
String str = String.valueOf(def);//把整型def变成字符串类str
String resstr = get(key,str);
try
{
result = Integer.parseInt(resstr);//把字符串类resstr变成整型result
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的浮点值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public float getFloat(String key,float def)
{
float result;
String str = String.valueOf(def);//把浮点型def变成字符串类str
String resstr = get(key,str);
try
{
result = Float.parseFloat(resstr);//把字符串类resstr变成浮点型result
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的双精度值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public double getDouble(String key,double def)
{
double result;
// 把double型def变成字符串类str
String str = String.valueOf(def);
String resstr = get(key,str);
try
{
// 把字符串类resstr变成double型result
result = Double.parseDouble(resstr);
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的长整型值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public long getLong(String key,long def)
{
long result;
String str = String.valueOf(def);//把long型def变成字符串类str
String resstr = get(key,str);
try
{
result = Long.parseLong(resstr);//把字符串类resstr变成long型result
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的字节数组值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public byte[] getByteArray(String key,byte[] def)
{
byte[] result;
String str = new String(def);//把byte[]型def变成字符串类str
String resstr = get(key,str);
result = resstr.getBytes();//把字符串类resstr变成byte[]型result
return result;
}
/**
* 设名字为key的节点的布尔型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putBoolean(String key, boolean value)
{
String str = String.valueOf(value); //将boolean型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的整型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putInt(String key,int value)
{
String str = String.valueOf(value); //将int型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的浮点型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putFloat(String key,float value)
{
String str = String.valueOf(value); //将float型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的双精度型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putDouble(String key,double value)
{
String str = String.valueOf(value); //将double型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的长整型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putLong(String key,long value)
{
String str = String.valueOf(value); //将long型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 删除某个节点。
* @param key 该节点的名称。
*/
public void removeNode(String key)
{
Node node = findNode(key); //查找该节点
if (node==null) //该节点不存在
{
return;
}
Node parentnode = node.getParentNode(); //取父节点
if (parentnode != null)
{
parentnode.removeChild(node); //删掉该节点
isDirty = true; //脏标志设为真
}
}
/**
* 清理某节点的所有子节点。
* @param key 该节点的名称。
*/
public void clear(String key)
{
Node node = findNode(key);//查找该节点
if (node == null) //未找到就抛出异常
{
throw new RuntimeException("InvalidName");
}
Node lastnode = null;
//依次把最后一个子节点清除
while (node.hasChildNodes())
{
lastnode = node.getLastChild();
node.removeChild(lastnode);
}
//若有子节点被清除,脏标志设为真
if (lastnode != null)
{
isDirty = true;
}
}
/**
* 查找某节点下的所有子节点的名字。
* @param key 被查节点的名字。
* @return String[] 子节点名字的字符串数组,如果不存在key对应的子节点,
* 则返回长度为0的空数组。
*/
public String[] childrenNames(String key)
{
Node node = findNode(key); //查找key节点
if (node==null)
{
return new String[0];
}
NodeList nl = node.getChildNodes();
LinkedList list = new LinkedList();
for (int i=0;i<nl.getLength();i++)
{
Node child = nl.item(i);
if (child.getNodeType()==Node.ELEMENT_NODE
&& child.hasChildNodes())
{
list.add(child.getNodeName());
}
}
String[] ret = new String[list.size()];
for (int i=0;i<ret.length;i++)
{
ret[i] = (String)list.get(i);
}
return ret;
}
/**
* 判断某个节点是否存在。
* @param key 被查节点的全名。
* @return true 节点存在返回true,节点不存在返回false。
*/
public boolean nodeExist(String key)
{
Node theNode = this.findNode(key);
if (theNode == null)
{
return false;
}
else if ( theNode.hasChildNodes())
{
return true;
}
else
{
return false;
}
}
/**
* 加载XML解析器驱动程序。
*/
private void loadXMLParser() throws IOException
{
//如果尚未加载过,则加载XML解析器驱动程序
if (builder == null)
{
try
{
factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
builder = factory.newDocumentBuilder();
}
catch (ParserConfigurationException ex)
{
throw new IOException("XML Parser load error:" +
ex.getLocalizedMessage());
}
}
}
/**
* 重新读取XML文件。
*/
public void load() throws IOException
{
loadXMLParser();
//解析配置文件
try
{
this.doc = builder.parse(file);
}
catch (SAXException ex)
{
ex.printStackTrace();
String message = ex.getMessage();
Exception e = ex.getException();
if (e!=null)
{
message += "embedded exception:" + e;
}
throw new IOException("XML file parse error:" + message);
}
root = doc.getDocumentElement();
/*
if (!"config".equals(root.getNodeName()))
{
throw new IOException("Config file format error, " +
"root node must be <config>");
}
*/
}
/**
* 把配置写进配置文件。
*/
public void flush() throws IOException
{
if(isDirty) //如果配置发生过修改
{
String proc = new URL(this.file).getProtocol().toLowerCase();
if (!proc.equalsIgnoreCase("file"))
{
throw new UnsupportedOperationException(
"Unsupport write config URL on protocal " + proc);
}
String fileName = new URL(this.file).getPath();
BufferedOutputStream bos = new BufferedOutputStream
(new FileOutputStream(fileName),2048);
PrintWriter pw = new PrintWriter(bos);
writeNode(doc,pw,0);//输出整个文档
pw.flush();
pw.close();
isDirty = false; //脏标志设为假
}
}
/**
* 将字符串中的大于号、小于号等特殊字符做转义处理。
* @param str 转义前字符串。
* @return 转义后的字符串。
*/
private String change(String str) throws IOException
{
if (str.indexOf('&')!=-1 || str.indexOf('<')!=-1
|| str.indexOf('>')!=-1)
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
byte temp;
byte[] ba1 = {'&','a','m','p',';'};
byte[] ba2 = {'&','l','t',';'};
byte[] ba3 = {'&','g','t',';'};
while( (temp = (byte)bis.read()) != -1 )
{
switch (temp)
{
case '&':
bos.write(ba1);
break;
case '<':
bos.write(ba2);
break;
case '>':
bos.write(ba3);
break;
default:
bos.write(temp);
}
}
return bos.toString();
}
return str; //不含有需转义的字符,则直接将原字符串返回
}
/**
* 取得CommonService配置的地址。
* @return 字符串类型的二维数组。
*/
public String[][] getServerAddrs()
{
int arrLength = childrenNames("common/aplComs/addrs").length;
String[][] aplArr= new String[arrLength][2];
if (arrLength==0)
{
return null;
}
for (int i=0;i<arrLength;i++)
{
String ip = this.get("common/aplComs/addrs/addr" + (i+1)+ "/ip","");
String port = this.get("common/aplComs/addrs/addr" + (i+1) + "/port","");
aplArr[i][0]= ip;
aplArr[i][1]= port;
}
return aplArr;
}
/**
* 取得系统监控配置的监控路径。
* @return 字符串类型的数组。
*/
public String[] getMonitorPath()
{
int arrLength = childrenNames("common/systemMonitor/paths").length;
String[] pathArr= new String[arrLength];
if (arrLength==0)
{
return null;
}
for (int i=0;i<arrLength;i++)
{
String path = this.get("common/systemMonitor/paths/path" + (i+1),"");
pathArr[i]= path;
}
return pathArr;
}
/**
* 测试入口。
*/
public static void main(String[] args) throws Exception
{
/*
c = new Cfg("testcfg.xml",true);
c.put("a/b","汉字");
c.put("c","");
c.put("a","avalusaaaaaaaaae");
c.flush();
System.out.println(" Config file content:");
BufferedReader in = new BufferedReader(new FileReader("testcfg.xml"));
String line;
while((line=in.readLine())!=null)
{
System.out.println(line);
}
*/
XMLProcess c = new XMLProcess("testcfg.xml",false);
/*String[] arr = c.childrenNames("common/logConfig");
for(int i = 0;i < arr.length;i++)
{
System.out.println("arr" + i + "=" + arr[i]);
}*/
/*c.clear("common/aplComs/addrs/addr3");
c.flush();*/
/*Node n = c.findNode("common/aplComs/addrs/addr3");*/
/*c.isDirty=true;
c.flush();*/
/*System.out.println(c.get(null,"def"));*/
/*System.out.println(c.getBoolean("common/logConfig/logLevel",false));*/
/*byte[] arr = c.getByteArray("common/logConfig/logLevel","aaa".getBytes());
for(int i = 0;i < arr.length;i++)
{
System.out.println("arr" + i + "=" + arr[i]);
System.out.println((char) arr[i]);
}
System.out.println(new String(arr));
System.out.println((char)110);
System.out.println((byte)'a');*/
/*System.out.println(c.getDouble("common/logConfig/maxLogFileLength",1));*/
/*System.out.println(c.getFloat("common/logConfig/maxLogFileLength",1));*/
/*System.out.println(c.getInt("common/logConfig/maxLogFileLength",1));*/
/*System.out.println(c.getLong("common/logConfig/maxLogFileLength",1));*/
/*String[] arr = (c.getMonitorPath());
if(arr != null)
{
for(int i = 0;i < arr.length;i++)
{
System.out.println("arr" + i + "=" + arr[i]);
}
}
else
{
System.out.println("arr=null");
}*/
/*String[][] arr = c.getServerAddrs();
if(arr != null)
{
for(int i = 0;i < arr.length;i++)
{
System.out.println("ip" + i + "=" + arr[i][0]);
System.out.println("port" + i + "=" + arr[i][1]);
}
}
else
{
System.out.println("arr=null");
}*/
/*c.load();*/
/*System.out.println(c.nodeExist("wskf"));*/
c.put("common/logConfig/logLevel","warn");
c.flush();
}
}
---------------------------------------------------------
引用:http://blog.csdn.net/sunlen/archive/2005/03/21/325292.aspx
在现在很多采用java开发的基于b\s结构的系统中,经常将一些配置参加放到一个xml文件中,然后在这个文件中取参数,这样减少了hard code的情况。下面这个类就是用来解析xml文件的。具体使用参考main方法的的写法。
/**
* filename: XMLProcess.java
* description: XML文件解析
* date: 2004-12-07
* @author sunlen
*
* History: // 历史修改记录
* <author> <time> <version > <desc>
*/
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import java.net.*;
public class XMLProcess
{
/** XML解析器工厂。*/
private static DocumentBuilderFactory factory;
/** XML解析器。*/
private static DocumentBuilder builder;
/** XML头。*/
private static final String XML_HEAD = "<?xml version=\"1.0\" encoding=\"gb2312\"?>";
/** 缩进前缀。*/
private static String indent = " ";
/** 该配置内存中数据是否与配置文件内容一致,不一致则为脏。*/
private boolean isDirty;
/** 代表该配置文件的文档类。*/
private Document doc;
/** 配置根节点。*/
private Element root;
/** 配置文件名。*/
private String file;
/**
* 创建配置读取对象。
* @param url 保存配置信息的XML文件路径。
*/
public XMLProcess(String url) throws IOException
{
this(url,false);
}
/**
* 创建配置读取对象。
* @param url 保存配置信息的XML文件路径。
* @param create 当配置文件不存在时,是否允许新建文件。
* @throws IOException 配置文件访问或内容解析异常。
*/
public XMLProcess(String url, boolean create) throws IOException
{
//得到配置信息
if (url==null)
{
throw new IllegalArgumentException("url is null");
}
if (url.indexOf(':')>1)
{
this.file = url;
}
else
{
this.file = new File(url).toURL().toString();
}
//为了检查参数file的合法性,如传的参数不合法,则抛出异常,调用者对其进行出错处理
new URL(this.file); //创建文件对象
try
{
load(); //读取配置文件
}
catch (FileNotFoundException ex)
{
if(!create)
{ //文件不存在,且不允许新建
throw ex;
}
else
{ //文件不存在,但允许新建
loadXMLParser(); //加载XML解析器
doc = builder.newDocument(); //创建空文档对象
root = doc.createElement("config");
doc.appendChild(root); //增加根节点
isDirty = true;
flush(); //保存到文件
return;
}
}
}
/**
* 输出缩进空格。
* @param pw 输出目的地。
* @param level 缩进深度。
*/
private static void writeIndent(PrintWriter pw,int level)
{
for (int i=0;i<level;i++)
{
pw.print(indent);
}
}
/**
* 以XML格式递归输出一个节点。
* @param node 输出起始节点。
* @param pw 输出目的地。
* @param 递归调用的深度标记,请输入0。
*/
private static void writeNode(Node node, PrintWriter pw, int deep)
{
switch (node.getNodeType())
{
case Node.COMMENT_NODE: //注释节点
writeIndent(pw,deep);
pw.print("<!--");
pw.print(node.getNodevalue());
pw.println("-->");
return;
case Node.TEXT_NODE: //文本节点
String value = node.getNodevalue().trim(); //文本trim防止破坏缩进格式
if (value.length()==0)
{
return;
}
writeIndent(pw,deep);
for (int i=0;i<value.length();i++)
{
char c = value.charAt(i);
switch(c)
{
case '<':
pw.print("<");
break;
case '>':
pw.print("<");
break;
case '&':
pw.print("&");
break;
case '\'':
pw.print("'");
break;
case '\"':
pw.print(""");
break;
default:
pw.print(c);
}
}
pw.println();
return;
case Node.ELEMENT_NODE: //标记节点
if (!node.hasChildNodes())
{
return;
}
for (int i=0;i<deep;i++)
{
pw.print(indent);
}
String nodeName = node.getNodeName();
pw.print('<');
pw.print(nodeName);
//输出属性
NamedNodeMap nnm = node.getAttributes();
if (nnm!=null)
{
for (int i=0; i<nnm.getLength(); i++)
{
Node attr = nnm.item(i);
pw.print(' ');
pw.print(attr.getNodeName());
pw.print("=\"");
pw.print(attr.getNodevalue());
pw.print('\"');
}
}
//输出子节点
if (node.hasChildNodes())
{
NodeList children = node.getChildNodes();
if (children.getLength()==0)
{
pw.print('<');
pw.print(nodeName);
pw.println("/>");
return;
}
if (children.getLength()==1)
{
Node n = children.item(0);
if(n.getNodeType()==Node.TEXT_NODE)
{
String v = n.getNodevalue();
if (v!=null)
{
v = v.trim();
}
if (v==null||v.length()==0)
{
pw.println(" />");
return;
}
else
{
pw.print('>');
pw.print(v);
pw.print("</");
pw.print(nodeName);
pw.println('>');
return;
}
}
}
pw.println(">");
for (int i=0;i<children.getLength();i++)
{
writeNode(children.item(i),pw,deep+1);
}
for (int i=0;i<deep;i++)
{
pw.print(indent);
}
pw.print("</");
pw.print(nodeName);
pw.println(">");
}
else
{
pw.println("/>");
}
return;
case Node.DOCUMENT_NODE: //文档节点
pw.println(XML_HEAD);
NodeList nl= node.getChildNodes();
for (int i=0;i<nl.getLength();i++)
{
writeNode(nl.item(i),pw,0);
}
return;
}
}
/**
* 根据key指定的关键字查找节点,在查找的过程中顺便将不存在的节点创建出来。
* @param key 所查找节点的关键字。
* @return 返回查到的节点,没查到则返回null。
*/
public Node findNode(String key)
{
Node ancestor = root;
for (StringTokenizer st = new StringTokenizer(key,"/");
st.hasMoreTokens();)
{
String nodeName = st.nextToken();
NodeList nl = ancestor.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{
Node n = nl.item(i);
if (nodeName.equals(n.getNodeName()))
{
ancestor = n;
//到达key的最低一级了
if (!st.hasMoreTokens())
{
return n;
}
break;
}
}
}
return null;
}
/**
* 根据key指定的关键字创建节点,将会把key代表的整个路径上的节点都创建出来。
* @param key 所查找节点的关键字。
* @return 返回最底层节点,即使已经存在,没有创建新节点。
*/
private Node createNode(String key)
{
Node ancestor = root;
token:
for (StringTokenizer st = new StringTokenizer(key,"/");
st.hasMoreTokens();)
{
String nodeName = st.nextToken();
NodeList nl = ancestor.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{
Node n = nl.item(i);
//该级子节点存在则继续找下一级子节点
if (nodeName.equals(n.getNodeName()))
{
ancestor = n;
if (st.hasMoreTokens())
{
continue token;
}
else
{
return ancestor;
}
}
}
//该级子节点不存在
for(;;) //死循环
{
Node n = doc.createElement(nodeName);
ancestor.appendChild(n);
ancestor = n;
if(!st.hasMoreTokens())
{
return ancestor;
}
nodeName = st.nextToken();
}
}
return null; //不可能执行到这里
}
/**
* 根据key指定的关键字查找节点,在查找的过程中顺便将不存在的节点创建出来。
* @param ancestor 以该节点为祖先开始查找。
* @param key 所查找节点的关键字。
* @return 返回查到的节点,没查到则返回null。
*/
private Node createNode(Node ancestor, String key)
{
searchToken: //用来跳出两层循环用的标记
for (StringTokenizer st = new StringTokenizer(key,"/");
st.hasMoreTokens();)
{
String nodeName = st.nextToken();
NodeList nl = ancestor.getChildNodes();
for (int i=0; i<nl.getLength(); i++)
{
if (nodeName.equals(nl.item(i).getNodeName()))
{
ancestor = nl.item(i);
continue searchToken;
}
}
return null;
}
return ancestor;
}
/**
* 取名字为key的节点的值。如果该节点存在,但无内容则返回空字符串:""
* @param key 和该关键字关联的配置项的值将被返回。
* @param def 若key对应的配置项不存在,则返回该值。
* @exception NullPointerException key值为null。
*/
public String get(String key, String def)
{
if (key == null)
{
throw new NullPointerException("parameter key is null");
}
Node node = findNode(key);
if (node==null) //节点不存在返回空
{
return def;
}
NodeList nl = node.getChildNodes();
for (int i=0;i<nl.getLength();i++)
{
if (nl.item(i).getNodeType()==Node.TEXT_NODE)
{
return nl.item(i).getNodevalue().trim();
}
}
node.appendChild(doc.createTextNode(def));
return def;
}
/**
* 设名字为key的节点的值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
* @exception NullPointerException 传入的key或value为null。
*/
public void put(String key, String value)
{
if (key == null)
{
throw new NullPointerException("parameter key is null");
}
if (value == null)
{
throw new NullPointerException("parameter value is null");
}
value = value.trim();
Node node = createNode(key);
//node节点的第一个文本子节点(不包括trim后为空的)放置该节点的值
NodeList nl = node.getChildNodes();
for (int i=0;i<nl.getLength();i++)
{
Node child = nl.item(i);
if (child.getNodeType()==Node.TEXT_NODE) //遇到第一个文本子节点
{
String childvalue = child.getNodevalue();
if (childvalue==null)
{
continue;
}
childvalue = childvalue.trim();
if (childvalue.length()==0)
{
continue;
}
//put的值和原来一样,直接返回即可
if (childvalue.equals(value))
{
return;
}
else
{
child.setNodevalue(value);
isDirty = true;
return;
}
}
}
//没有trim后还有内容的文本子节点
if (nl.getLength()==0) //节点为空
{
node.appendChild(doc.createTextNode(value));
}
else //节点非空
{
Node f = node.getFirstChild();
if (f.getNodeType()==Node.TEXT_NODE)
{
f.setNodevalue(value);
}
else
{
node.insertBefore(doc.createTextNode(value),f);
}
}
isDirty = true; //修改后,脏标记设为真
}
/**
* 取名字为key的节点的布尔值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public boolean getBoolean(String key, boolean def)
{
String str = String.valueOf(def); //把布尔型def变成字符串类str
boolean result;
String resstr = get(key,str);
Boolean resboolean = Boolean.valueOf(resstr);
result = resboolean.booleanvalue();
return result;
}
/**
* 取名字为key的节点的整型值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public int getInt(String key,int def)
{
int result;
String str = String.valueOf(def);//把整型def变成字符串类str
String resstr = get(key,str);
try
{
result = Integer.parseInt(resstr);//把字符串类resstr变成整型result
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的浮点值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public float getFloat(String key,float def)
{
float result;
String str = String.valueOf(def);//把浮点型def变成字符串类str
String resstr = get(key,str);
try
{
result = Float.parseFloat(resstr);//把字符串类resstr变成浮点型result
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的双精度值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public double getDouble(String key,double def)
{
double result;
// 把double型def变成字符串类str
String str = String.valueOf(def);
String resstr = get(key,str);
try
{
// 把字符串类resstr变成double型result
result = Double.parseDouble(resstr);
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的长整型值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public long getLong(String key,long def)
{
long result;
String str = String.valueOf(def);//把long型def变成字符串类str
String resstr = get(key,str);
try
{
result = Long.parseLong(resstr);//把字符串类resstr变成long型result
}
catch(NumberFormatException e)
{
return def;
}
return result;
}
/**
* 取名字为key的节点的字节数组值。
* @param key 取值节点对象的名字。
* @param def 若没有取到,则返回该值。
*/
public byte[] getByteArray(String key,byte[] def)
{
byte[] result;
String str = new String(def);//把byte[]型def变成字符串类str
String resstr = get(key,str);
result = resstr.getBytes();//把字符串类resstr变成byte[]型result
return result;
}
/**
* 设名字为key的节点的布尔型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putBoolean(String key, boolean value)
{
String str = String.valueOf(value); //将boolean型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的整型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putInt(String key,int value)
{
String str = String.valueOf(value); //将int型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的浮点型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putFloat(String key,float value)
{
String str = String.valueOf(value); //将float型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的双精度型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putDouble(String key,double value)
{
String str = String.valueOf(value); //将double型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 设名字为key的节点的长整型值。
* @param key 设值节点对象的名字。
* @param value 所设的值。
*/
public void putLong(String key,long value)
{
String str = String.valueOf(value); //将long型转换成String类型
try
{
put(key,str);
}
catch(RuntimeException e)
{
throw e;
}
}
/**
* 删除某个节点。
* @param key 该节点的名称。
*/
public void removeNode(String key)
{
Node node = findNode(key); //查找该节点
if (node==null) //该节点不存在
{
return;
}
Node parentnode = node.getParentNode(); //取父节点
if (parentnode != null)
{
parentnode.removeChild(node); //删掉该节点
isDirty = true; //脏标志设为真
}
}
/**
* 清理某节点的所有子节点。
* @param key 该节点的名称。
*/
public void clear(String key)
{
Node node = findNode(key);//查找该节点
if (node == null) //未找到就抛出异常
{
throw new RuntimeException("InvalidName");
}
Node lastnode = null;
//依次把最后一个子节点清除
while (node.hasChildNodes())
{
lastnode = node.getLastChild();
node.removeChild(lastnode);
}
//若有子节点被清除,脏标志设为真
if (lastnode != null)
{
isDirty = true;
}
}
/**
* 查找某节点下的所有子节点的名字。
* @param key 被查节点的名字。
* @return String[] 子节点名字的字符串数组,如果不存在key对应的子节点,
* 则返回长度为0的空数组。
*/
public String[] childrenNames(String key)
{
Node node = findNode(key); //查找key节点
if (node==null)
{
return new String[0];
}
NodeList nl = node.getChildNodes();
LinkedList list = new LinkedList();
for (int i=0;i<nl.getLength();i++)
{
Node child = nl.item(i);
if (child.getNodeType()==Node.ELEMENT_NODE
&& child.hasChildNodes())
{
list.add(child.getNodeName());
}
}
String[] ret = new String[list.size()];
for (int i=0;i<ret.length;i++)
{
ret[i] = (String)list.get(i);
}
return ret;
}
/**
* 判断某个节点是否存在。
* @param key 被查节点的全名。
* @return true 节点存在返回true,节点不存在返回false。
*/
public boolean nodeExist(String key)
{
Node theNode = this.findNode(key);
if (theNode == null)
{
return false;
}
else if ( theNode.hasChildNodes())
{
return true;
}
else
{
return false;
}
}
/**
* 加载XML解析器驱动程序。
*/
private void loadXMLParser() throws IOException
{
//如果尚未加载过,则加载XML解析器驱动程序
if (builder == null)
{
try
{
factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
builder = factory.newDocumentBuilder();
}
catch (ParserConfigurationException ex)
{
throw new IOException("XML Parser load error:" +
ex.getLocalizedMessage());
}
}
}
/**
* 重新读取XML文件。
*/
public void load() throws IOException
{
loadXMLParser();
//解析配置文件
try
{
this.doc = builder.parse(file);
}
catch (SAXException ex)
{
ex.printStackTrace();
String message = ex.getMessage();
Exception e = ex.getException();
if (e!=null)
{
message += "embedded exception:" + e;
}
throw new IOException("XML file parse error:" + message);
}
root = doc.getDocumentElement();
/*
if (!"config".equals(root.getNodeName()))
{
throw new IOException("Config file format error, " +
"root node must be <config>");
}
*/
}
/**
* 把配置写进配置文件。
*/
public void flush() throws IOException
{
if(isDirty) //如果配置发生过修改
{
String proc = new URL(this.file).getProtocol().toLowerCase();
if (!proc.equalsIgnoreCase("file"))
{
throw new UnsupportedOperationException(
"Unsupport write config URL on protocal " + proc);
}
String fileName = new URL(this.file).getPath();
BufferedOutputStream bos = new BufferedOutputStream
(new FileOutputStream(fileName),2048);
PrintWriter pw = new PrintWriter(bos);
writeNode(doc,pw,0);//输出整个文档
pw.flush();
pw.close();
isDirty = false; //脏标志设为假
}
}
/**
* 将字符串中的大于号、小于号等特殊字符做转义处理。
* @param str 转义前字符串。
* @return 转义后的字符串。
*/
private String change(String str) throws IOException
{
if (str.indexOf('&')!=-1 || str.indexOf('<')!=-1
|| str.indexOf('>')!=-1)
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
byte temp;
byte[] ba1 = {'&','a','m','p',';'};
byte[] ba2 = {'&','l','t',';'};
byte[] ba3 = {'&','g','t',';'};
while( (temp = (byte)bis.read()) != -1 )
{
switch (temp)
{
case '&':
bos.write(ba1);
break;
case '<':
bos.write(ba2);
break;
case '>':
bos.write(ba3);
break;
default:
bos.write(temp);
}
}
return bos.toString();
}
return str; //不含有需转义的字符,则直接将原字符串返回
}
/**
* 取得CommonService配置的地址。
* @return 字符串类型的二维数组。
*/
public String[][] getServerAddrs()
{
int arrLength = childrenNames("common/aplComs/addrs").length;
String[][] aplArr= new String[arrLength][2];
if (arrLength==0)
{
return null;
}
for (int i=0;i<arrLength;i++)
{
String ip = this.get("common/aplComs/addrs/addr" + (i+1)+ "/ip","");
String port = this.get("common/aplComs/addrs/addr" + (i+1) + "/port","");
aplArr[i][0]= ip;
aplArr[i][1]= port;
}
return aplArr;
}
/**
* 取得系统监控配置的监控路径。
* @return 字符串类型的数组。
*/
public String[] getMonitorPath()
{
int arrLength = childrenNames("common/systemMonitor/paths").length;
String[] pathArr= new String[arrLength];
if (arrLength==0)
{
return null;
}
for (int i=0;i<arrLength;i++)
{
String path = this.get("common/systemMonitor/paths/path" + (i+1),"");
pathArr[i]= path;
}
return pathArr;
}
/**
* 测试入口。
*/
public static void main(String[] args) throws Exception
{
/*
c = new Cfg("testcfg.xml",true);
c.put("a/b","汉字");
c.put("c","");
c.put("a","avalusaaaaaaaaae");
c.flush();
System.out.println(" Config file content:");
BufferedReader in = new BufferedReader(new FileReader("testcfg.xml"));
String line;
while((line=in.readLine())!=null)
{
System.out.println(line);
}
*/
XMLProcess c = new XMLProcess("testcfg.xml",false);
/*String[] arr = c.childrenNames("common/logConfig");
for(int i = 0;i < arr.length;i++)
{
System.out.println("arr" + i + "=" + arr[i]);
}*/
/*c.clear("common/aplComs/addrs/addr3");
c.flush();*/
/*Node n = c.findNode("common/aplComs/addrs/addr3");*/
/*c.isDirty=true;
c.flush();*/
/*System.out.println(c.get(null,"def"));*/
/*System.out.println(c.getBoolean("common/logConfig/logLevel",false));*/
/*byte[] arr = c.getByteArray("common/logConfig/logLevel","aaa".getBytes());
for(int i = 0;i < arr.length;i++)
{
System.out.println("arr" + i + "=" + arr[i]);
System.out.println((char) arr[i]);
}
System.out.println(new String(arr));
System.out.println((char)110);
System.out.println((byte)'a');*/
/*System.out.println(c.getDouble("common/logConfig/maxLogFileLength",1));*/
/*System.out.println(c.getFloat("common/logConfig/maxLogFileLength",1));*/
/*System.out.println(c.getInt("common/logConfig/maxLogFileLength",1));*/
/*System.out.println(c.getLong("common/logConfig/maxLogFileLength",1));*/
/*String[] arr = (c.getMonitorPath());
if(arr != null)
{
for(int i = 0;i < arr.length;i++)
{
System.out.println("arr" + i + "=" + arr[i]);
}
}
else
{
System.out.println("arr=null");
}*/
/*String[][] arr = c.getServerAddrs();
if(arr != null)
{
for(int i = 0;i < arr.length;i++)
{
System.out.println("ip" + i + "=" + arr[i][0]);
System.out.println("port" + i + "=" + arr[i][1]);
}
}
else
{
System.out.println("arr=null");
}*/
/*c.load();*/
/*System.out.println(c.nodeExist("wskf"));*/
c.put("common/logConfig/logLevel","warn");
c.flush();
}
}
---------------------------------------------------------
引用:http://blog.csdn.net/sunlen/archive/2005/03/21/325292.aspx
回复Comments
{commenttime}{commentauthor}
{CommentUrl}
{commentcontent}