java 5中的properties类现在可以使用xml存取,通过loadfromxml和storetoxml方法实现。假设有下面这个属性表:
windowsize: 400,400
windowlocation: 456,300
使用storetoxml后会得到这样的xml文件
<?xml version="1.0" encoding="utf-8"?>
<!doctype properties system "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>comment</comment>
<entry key="windowlocation">400,400</entry>
<entry key="windowsize">456,300</entry>
</properties>
<!doctype properties system "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>comment</comment>
<entry key="windowlocation">400,400</entry>
<entry key="windowsize">456,300</entry>
</properties>
但是如果要获得更具层次感的属性文件,可以使用这里我写的一个utility。它建立在一个读取和存储xml的类库上。这个类库采集于columba project的util包,并有所修改。
首先是xmlelement,用于表示xml文件里的一个entry
/*
* @(#)xmlelement.java
* created on 2005-8-12
*/
package com.allenstudio.ir.util;
* @(#)xmlelement.java
* created on 2005-8-12
*/
package com.allenstudio.ir.util;
import java.util.enumeration;
import java.util.hashtable;
import java.util.iterator;
import java.util.list;
import java.util.observable;
import java.util.vector;
import java.util.hashtable;
import java.util.iterator;
import java.util.list;
import java.util.observable;
import java.util.vector;
/**
* the xmlelement is a generic containment class for elements within an xml
* file.
* <p>
*
* it extends observable which should be used for gui elements which are
* interested in configuration changes.
* <p>
*
* show interested in:
*
* <pre>
* xmlelement.addobserver(yourobserver);
* </pre>
*
* <p>
* when making bigger changes on xmlelement and probably its subnodes and/or a
* greater number of attributes at once, you should just change xmlelement
* directly and manually notify the observers by calling:
* <p>
*
* <pre>
* xmlelement.setchanged();
* xmlelement.notifyobservers();
* </pre>
*
* <p>
* there a good introduction for the observable/observer pattern in
* model/view/controller based applications at www.javaworld.com: -
* {@link http://www.javaworld.com/javaworld/jw-10-1996/jw-10-howto.html}
*
* @author fdietz
*/
public class xmlelement extends observable implements cloneable {
string name;
* the xmlelement is a generic containment class for elements within an xml
* file.
* <p>
*
* it extends observable which should be used for gui elements which are
* interested in configuration changes.
* <p>
*
* show interested in:
*
* <pre>
* xmlelement.addobserver(yourobserver);
* </pre>
*
* <p>
* when making bigger changes on xmlelement and probably its subnodes and/or a
* greater number of attributes at once, you should just change xmlelement
* directly and manually notify the observers by calling:
* <p>
*
* <pre>
* xmlelement.setchanged();
* xmlelement.notifyobservers();
* </pre>
*
* <p>
* there a good introduction for the observable/observer pattern in
* model/view/controller based applications at www.javaworld.com: -
* {@link http://www.javaworld.com/javaworld/jw-10-1996/jw-10-howto.html}
*
* @author fdietz
*/
public class xmlelement extends observable implements cloneable {
string name;
string data;
hashtable<string, string> attributes;
list<xmlelement> subelements;
xmlelement parent;
/**
*
*
* constructor
*
*/
public xmlelement() {
subelements = new vector<xmlelement>();
this.attributes = new hashtable<string, string>(10);
}
*
*
* constructor
*
*/
public xmlelement() {
subelements = new vector<xmlelement>();
this.attributes = new hashtable<string, string>(10);
}
/**
* **
*
* constructor
*
* @param string
* name
*
*/
public xmlelement(string name) {
this.name = name;
this.attributes = new hashtable<string, string>(10);
subelements = new vector<xmlelement>();
data = "";
}
* **
*
* constructor
*
* @param string
* name
*
*/
public xmlelement(string name) {
this.name = name;
this.attributes = new hashtable<string, string>(10);
subelements = new vector<xmlelement>();
data = "";
}
/**
* **
*
* constructor
*
* @param string
* name
* @param hashtable
* attributes
*
*/
public xmlelement(string name, hashtable<string, string> attributes) {
this.name = name;
this.attributes = attributes;
subelements = new vector<xmlelement>();
}
* **
*
* constructor
*
* @param string
* name
* @param hashtable
* attributes
*
*/
public xmlelement(string name, hashtable<string, string> attributes) {
this.name = name;
this.attributes = attributes;
subelements = new vector<xmlelement>();
}
/**
* **
*
* constructor
*
* @param name
* string
* @param data
* string
*
*/
public xmlelement(string name, string data) {
this.name = name;
this.data = data;
subelements = new vector<xmlelement>();
this.attributes = new hashtable<string, string>(10);
}
* **
*
* constructor
*
* @param name
* string
* @param data
* string
*
*/
public xmlelement(string name, string data) {
this.name = name;
this.data = data;
subelements = new vector<xmlelement>();
this.attributes = new hashtable<string, string>(10);
}
/**
* add attribute to this xml element.
*
* @param name
* name of key
* @param value
* new attribute value
* @return old attribute value
*
*/
public object addattribute(string name, string value) {
if ((value != null) && (name != null)) {
object returnvalue = attributes.put(name, value);
* add attribute to this xml element.
*
* @param name
* name of key
* @param value
* new attribute value
* @return old attribute value
*
*/
public object addattribute(string name, string value) {
if ((value != null) && (name != null)) {
object returnvalue = attributes.put(name, value);
return returnvalue;
}
}
return null;
}
}
/**
* **
*
* @return string
* @param string
* name
*
*/
public string getattribute(string name) {
return ((string) attributes.get(name));
}
* **
*
* @return string
* @param string
* name
*
*/
public string getattribute(string name) {
return ((string) attributes.get(name));
}
public string getattribute(string name, string defaultvalue) {
if (getattribute(name) == null) {
addattribute(name, defaultvalue);
}
if (getattribute(name) == null) {
addattribute(name, defaultvalue);
}
return getattribute(name);
}
}
/**
* **
*
* @return string
* @param string
* name
*
*/
public hashtable<string, string> getattributes() {
return attributes;
}
* **
*
* @return string
* @param string
* name
*
*/
public hashtable<string, string> getattributes() {
return attributes;
}
/**
* **
*
*
* @param attrs
* hashtable to use as the attributes
*
*/
public void setattributes(hashtable<string, string> attrs) {
attributes = attrs;
}
* **
*
*
* @param attrs
* hashtable to use as the attributes
*
*/
public void setattributes(hashtable<string, string> attrs) {
attributes = attrs;
}
/**
* **
*
* @return enumeration
*
*/
public enumeration getattributenames() {
return (attributes.keys());
}
* **
*
* @return enumeration
*
*/
public enumeration getattributenames() {
return (attributes.keys());
}
/**
* **
*
* @return boolean
* @param xmlelement
* e
*
*/
public boolean addelement(xmlelement e) {
e.setparent(this);
* **
*
* @return boolean
* @param xmlelement
* e
*
*/
public boolean addelement(xmlelement e) {
e.setparent(this);
return (subelements.add(e));
}
}
public xmlelement removeelement(xmlelement e) {
xmlelement child = null;
xmlelement child = null;
for (int i = 0; i < subelements.size(); i++) {
child = (xmlelement) subelements.get(i);
child = (xmlelement) subelements.get(i);
// fixme -- this will most likely not work.
// you want the element removed if the contents are the same
// not just if the element reference is the same.
if (child == e) {
subelements.remove(i);
}
}
// you want the element removed if the contents are the same
// not just if the element reference is the same.
if (child == e) {
subelements.remove(i);
}
}
return (child);
}
}
public xmlelement removeelement(int index) {
return (xmlelement) subelements.remove(index);
}
return (xmlelement) subelements.remove(index);
}
public void removeallelements() {
subelements.clear();
}
subelements.clear();
}
/**
* convienience method for the treeview
*
* this method is modeled after the defaultmutabletreenode-class
*
* defaultmutabletreenode wraps xmlelement for this purpose
*
*/
public void removefromparent() {
if (parent == null) {
return;
}
* convienience method for the treeview
*
* this method is modeled after the defaultmutabletreenode-class
*
* defaultmutabletreenode wraps xmlelement for this purpose
*
*/
public void removefromparent() {
if (parent == null) {
return;
}
parent.removeelement(this);
parent = null;
}
parent = null;
}
public void append(xmlelement e) {
e.removefromparent();
e.removefromparent();
addelement(e);
}
}
/**
*
* convienience method for the treeview
*
* @param e
* @param index
*/
public void insertelement(xmlelement e, int index) {
e.removefromparent();
*
* convienience method for the treeview
*
* @param e
* @param index
*/
public void insertelement(xmlelement e, int index) {
e.removefromparent();
subelements.add(index, e);
e.setparent(this);
}
e.setparent(this);
}
/**
* **
*
* @return vector
*
*/
public list getelements() {
return subelements;
}
* **
*
* @return vector
*
*/
public list getelements() {
return subelements;
}
public int count() {
return subelements.size();
}
return subelements.size();
}
/**
* returns the element whose hierachy is indicated
* by <code>path</code>. the path is separated with
* periods(".").<br>
* <em>note: if one node has more than one elements
* that have the same name, that is, if its subnodes
* have the same path, only the first one is returned.
* </em>
* @return the first element qualified with the path
* @param path the path string of the specified element
*/
public xmlelement getelement(string path) {
int i = path.indexof(.);
string topname;
string subname;
* returns the element whose hierachy is indicated
* by <code>path</code>. the path is separated with
* periods(".").<br>
* <em>note: if one node has more than one elements
* that have the same name, that is, if its subnodes
* have the same path, only the first one is returned.
* </em>
* @return the first element qualified with the path
* @param path the path string of the specified element
*/
public xmlelement getelement(string path) {
int i = path.indexof(.);
string topname;
string subname;
if (i == 0) {
path = path.substring(1);
i = path.indexof(.);
}
path = path.substring(1);
i = path.indexof(.);
}
if (i > 0) {
topname = path.substring(0, i);
subname = path.substring(i + 1);
} else {
topname = path;
subname = null;
}
topname = path.substring(0, i);
subname = path.substring(i + 1);
} else {
topname = path;
subname = null;
}
int j;
for (j = 0; j < subelements.size(); j++) {
if (((xmlelement) subelements.get(j)).getname().equals(topname)) {
if (subname != null) {
return (((xmlelement) subelements.get(j))
.getelement(subname));
} else {
return ((xmlelement) subelements.get(j));
}
}
}
if (((xmlelement) subelements.get(j)).getname().equals(topname)) {
if (subname != null) {
return (((xmlelement) subelements.get(j))
.getelement(subname));
} else {
return ((xmlelement) subelements.get(j));
}
}
}
return null;
}
}
public xmlelement getelement(int index) {
return (xmlelement) subelements.get(index);
}
return (xmlelement) subelements.get(index);
}
/**
* adds a sub element to this one. the path
* is separated with dots(".").
*
* @return the <code>xmlelement</code> added
* @param path the subpath of the sub element to add
*
*/
public xmlelement addsubelement(string path) {
xmlelement parent = this;
xmlelement child;
string name;
* adds a sub element to this one. the path
* is separated with dots(".").
*
* @return the <code>xmlelement</code> added
* @param path the subpath of the sub element to add
*
*/
public xmlelement addsubelement(string path) {
xmlelement parent = this;
xmlelement child;
string name;
while (path.indexof(.) != -1) {
name = path.substring(0, path.indexof(.));
path = path.substring(path.indexof(.) + 1);
name = path.substring(0, path.indexof(.));
path = path.substring(path.indexof(.) + 1);
// if path startswith "/" -> skip
if (name.length() == 0)
continue;
if (name.length() == 0)
continue;
if (parent.getelement(name) != null) {
parent = parent.getelement(name);
} else {
child = new xmlelement(name);
parent = parent.getelement(name);
} else {
child = new xmlelement(name);
parent.addelement(child);
parent = child;
}
parent = child;
}
}
child = new xmlelement(path);
parent.addelement(child);
parent.addelement(child);
return child;
}
}
/**
* adds a sub element to this one
*
* @return xmlelement
* @param element
* the xmlelement to add
*
*/
public xmlelement addsubelement(xmlelement e) {
e.setparent(this);
subelements.add(e);
* adds a sub element to this one
*
* @return xmlelement
* @param element
* the xmlelement to add
*
*/
public xmlelement addsubelement(xmlelement e) {
e.setparent(this);
subelements.add(e);
return e;
}
}
/**
* adds a sub element to this one
*
* @return xmlelement
* @param name
* the name of the sub element to add
* @param data
* string data for this element
*/
public xmlelement addsubelement(string name, string data) {
xmlelement e = new xmlelement(name);
e.setdata(data);
e.setparent(this);
subelements.add(e);
* adds a sub element to this one
*
* @return xmlelement
* @param name
* the name of the sub element to add
* @param data
* string data for this element
*/
public xmlelement addsubelement(string name, string data) {
xmlelement e = new xmlelement(name);
e.setdata(data);
e.setparent(this);
subelements.add(e);
return e;
}
}
/**
* sets the parent element
*
* @param parent
* the xmlelement that contains this one
*
*/
public void setparent(xmlelement parent) {
this.parent = parent;
}
* sets the parent element
*
* @param parent
* the xmlelement that contains this one
*
*/
public void setparent(xmlelement parent) {
this.parent = parent;
}
/**
* gives the xmlelement containing the current element
*
* @return xmlelement
*
*/
public xmlelement getparent() {
return parent;
}
* gives the xmlelement containing the current element
*
* @return xmlelement
*
*/
public xmlelement getparent() {
return parent;
}
/**
* sets the data for this element
*
* @param d
* the string representation of the data
*
*/
public void setdata(string d) {
data = d;
}
* sets the data for this element
*
* @param d
* the string representation of the data
*
*/
public void setdata(string d) {
data = d;
}
/**
* returns the data associated with the current xml element
*
* @return string
*
*/
public string getdata() {
return data;
}
* returns the data associated with the current xml element
*
* @return string
*
*/
public string getdata() {
return data;
}
/**
* returns the name of the current xml element
*
* @return string
*
*/
public string getname() {
return name;
}
* returns the name of the current xml element
*
* @return string
*
*/
public string getname() {
return name;
}
/**
* **
*
* @param out
* outputstream to print the data to
*
*/
* **
*
* @param out
* outputstream to print the data to
*
*/
/*
* public void write(outputstream out) throws ioexception { printwriter pw =
* new printwriter(out); pw.println(" <?xml version=\"1.0\"
* encoding=\"utf-8\"?>"); if (subelements.size() > 0) { for (int i = 0; i <
* subelements.size(); i++) { ((xmlelement)
* subelements.get(i))._writesubnode(pw, 4); } } pw.flush(); }
*/
* public void write(outputstream out) throws ioexception { printwriter pw =
* new printwriter(out); pw.println(" <?xml version=\"1.0\"
* encoding=\"utf-8\"?>"); if (subelements.size() > 0) { for (int i = 0; i <
* subelements.size(); i++) { ((xmlelement)
* subelements.get(i))._writesubnode(pw, 4); } } pw.flush(); }
*/
/**
* prints sub nodes to the given data stream
*
* @param out
* printwriter to use for printing
* @param indent
* number of spaces to indent things
*
*/
* prints sub nodes to the given data stream
*
* @param out
* printwriter to use for printing
* @param indent
* number of spaces to indent things
*
*/
/*
* private void _writesubnode(printwriter out, int indent) throws
* ioexception { _writespace(out, indent); out.print(" <" + name); //if (
* attributes.size()>1) out.print(" ");
*
* for (enumeration e = attributes.keys(); e.hasmoreelements();) { string k =
* (string) e.nextelement(); out.print(k + "=\"" + attributes.get(k) + "\"
* b");
* } out.print(">");
*
* if (data != null && !data.equals("")) { if (data.length() > 20) {
* out.println(""); _writespace(out, indent + 2); } out.print(data); } if
* (subelements.size() > 0) { out.println(""); for (int i = 0; i <
* subelements.size(); i++) { ((xmlelement)
* subelements.get(i))._writesubnode( out, indent + 4); } _writespace(out,
* indent); } out.println(" </" + name + ">");
* }
*/
* private void _writesubnode(printwriter out, int indent) throws
* ioexception { _writespace(out, indent); out.print(" <" + name); //if (
* attributes.size()>1) out.print(" ");
*
* for (enumeration e = attributes.keys(); e.hasmoreelements();) { string k =
* (string) e.nextelement(); out.print(k + "=\"" + attributes.get(k) + "\"
* b");
* } out.print(">");
*
* if (data != null && !data.equals("")) { if (data.length() > 20) {
* out.println(""); _writespace(out, indent + 2); } out.print(data); } if
* (subelements.size() > 0) { out.println(""); for (int i = 0; i <
* subelements.size(); i++) { ((xmlelement)
* subelements.get(i))._writesubnode( out, indent + 4); } _writespace(out,
* indent); } out.println(" </" + name + ">");
* }
*/
/**
* prints out a given number of spaces
*
* @param out
* printwriter to use for printing
* @param numspaces
* number of spaces to print
*
*/
* prints out a given number of spaces
*
* @param out
* printwriter to use for printing
* @param numspaces
* number of spaces to print
*
*/
/*
* private void _writespace(printwriter out, int numspaces) throws
* ioexception {
*
* for (int i = 0; i < numspaces; i++) out.print(" "); }
*
* public static void printnode(xmlelement node, string indent) { string
* data = node.getdata(); if (data == null || data.equals("")) {
* system.out.println(indent + node.getname()); } else {
* system.out.println(indent + node.getname() + " = " + data + ""); }
* vector subs = node.getelements(); int i, j; for (i = 0; i < subs.size();
* i++) { printnode((xmlelement) subs.get(i), indent + " "); } }
*/
public static void printnode(xmlelement node, string indent) {
string data = node.getdata();
* private void _writespace(printwriter out, int numspaces) throws
* ioexception {
*
* for (int i = 0; i < numspaces; i++) out.print(" "); }
*
* public static void printnode(xmlelement node, string indent) { string
* data = node.getdata(); if (data == null || data.equals("")) {
* system.out.println(indent + node.getname()); } else {
* system.out.println(indent + node.getname() + " = " + data + ""); }
* vector subs = node.getelements(); int i, j; for (i = 0; i < subs.size();
* i++) { printnode((xmlelement) subs.get(i), indent + " "); } }
*/
public static void printnode(xmlelement node, string indent) {
string data = node.getdata();
if ((data == null) || data.equals("")) {
system.out.println(indent + node.getname());
} else {
system.out.println(indent + node.getname() + " = " + data + "");
}
system.out.println(indent + node.getname());
} else {
system.out.println(indent + node.getname() + " = " + data + "");
}
// print attributes
for (enumeration enumeration = node.getattributes().keys(); enumeration
.hasmoreelements();) {
string key = (string) enumeration.nextelement();
string value = node.getattribute(key);
system.out.println(indent + key + ":" + value);
}
for (enumeration enumeration = node.getattributes().keys(); enumeration
.hasmoreelements();) {
string key = (string) enumeration.nextelement();
string value = node.getattribute(key);
system.out.println(indent + key + ":" + value);
}
list subs = node.getelements();
for (iterator it = subs.iterator(); it.hasnext();) {
printnode((xmlelement) it.next(), indent + " ");
printnode((xmlelement) it.next(), indent + " ");
// for (i = 0; i < subs.size(); i++) {
// printnode((xmlelement) subs.get(i), indent + " ");
}
}
// printnode((xmlelement) subs.get(i), indent + " ");
}
}
/** {@inheritdoc} */
@suppresswarnings("unchecked")
@override
public object clone() {
try {
xmlelement clone = (xmlelement) super.clone(); // creates a shallow
// copy of this
// object
@suppresswarnings("unchecked")
@override
public object clone() {
try {
xmlelement clone = (xmlelement) super.clone(); // creates a shallow
// copy of this
// object
if (attributes != null) {
clone.setattributes((hashtable<string, string>) getattributes().clone());
}
clone.setattributes((hashtable<string, string>) getattributes().clone());
}
if (subelements != null) {
clone.subelements = new vector();
clone.subelements = new vector();
list childs = getelements();
xmlelement child;
xmlelement child;
for (iterator it = childs.iterator(); it.hasnext();) {
child = (xmlelement) it.next();
child = (xmlelement) it.next();
// for( int i=0; i<childs.size(); i++ ) {
// child = (xmlelement) childs.get(i);
clone.addsubelement((xmlelement) child.clone());
}
}
// child = (xmlelement) childs.get(i);
clone.addsubelement((xmlelement) child.clone());
}
}
return clone;
} catch (clonenotsupportedexception cnse) {
throw new internalerror("could not clone xmlelement: " + cnse);
}
}
} catch (clonenotsupportedexception cnse) {
throw new internalerror("could not clone xmlelement: " + cnse);
}
}
/**
* sets the name.
*
* @param name
* the name to set
*/
public void setname(string name) {
this.name = name;
}
* sets the name.
*
* @param name
* the name to set
*/
public void setname(string name) {
this.name = name;
}
/**
* notify all observers.
*
* @see java.util.observable#notifyobservers()
*/
@override
public void notifyobservers() {
setchanged();
super.notifyobservers();
}
* notify all observers.
*
* @see java.util.observable#notifyobservers()
*/
@override
public void notifyobservers() {
setchanged();
super.notifyobservers();
}
/**
* returns true if the specified objects are equal. they are equal if they
* are both null or if the <code>equals()</code> method return true. (
* <code>obj1.equals(obj2)</code>).
*
* @param obj1
* first object to compare with.
* @param obj2
* second object to compare with.
* @return true if they represent the same object; false if one of them is
* null or the <code>equals()</code> method returns false.
*/
private boolean equals(object obj1, object obj2) {
boolean equal = false;
* returns true if the specified objects are equal. they are equal if they
* are both null or if the <code>equals()</code> method return true. (
* <code>obj1.equals(obj2)</code>).
*
* @param obj1
* first object to compare with.
* @param obj2
* second object to compare with.
* @return true if they represent the same object; false if one of them is
* null or the <code>equals()</code> method returns false.
*/
private boolean equals(object obj1, object obj2) {
boolean equal = false;
if ((obj1 == null) && (obj2 == null)) {
equal = true;
} else if ((obj1 != null) && (obj2 != null)) {
equal = obj1.equals(obj2);
}
equal = true;
} else if ((obj1 != null) && (obj2 != null)) {
equal = obj1.equals(obj2);
}
return equal;
}
}
/** {@inheritdoc}
*recursive comparison.
*/
@override
public boolean equals(object obj) {
boolean equal = false;
*recursive comparison.
*/
@override
public boolean equals(object obj) {
boolean equal = false;
if ((obj != null) && (obj instanceof xmlelement)) {
xmlelement other = (xmlelement) obj;
xmlelement other = (xmlelement) obj;
if (equals(attributes, other.attributes)
&& equals(data, other.data) && equals(name, other.name)
&& equals(subelements, other.subelements)) {
equal = true;
}
}
&& equals(data, other.data) && equals(name, other.name)
&& equals(subelements, other.subelements)) {
equal = true;
}
}
return equal;
}
}
/** {@inheritdoc} */
@override
public int hashcode() {
//hashcode value should be buffered.
int hashcode = 23;
@override
public int hashcode() {
//hashcode value should be buffered.
int hashcode = 23;
if (attributes != null) {
hashcode += (attributes.hashcode() * 13);
}
hashcode += (attributes.hashcode() * 13);
}
if (data != null) {
hashcode += (data.hashcode() * 17);
}
hashcode += (data.hashcode() * 17);
}
if (name != null) {
hashcode += (name.hashcode() * 29);
}
hashcode += (name.hashcode() * 29);
}
if (subelements != null) {
hashcode += (subelements.hashcode() * 57);
}
hashcode += (subelements.hashcode() * 57);
}
return hashcode;
}
}
}
}
然后是xmlio,用于读写。
}
*/
public xmlio(url url) {
super();
this.url = url;
}
在上面的代码中,inspirento是我的项目,可以根据情况修改。实际这个类是使用在整个程序的配置获取和修改的。如果用它处理前面的属性,可以得到这样的文件,可以看到它有层次感,更便于处理和阅读。
/*
* @(#)xmlio.java
* created on 2005-8-12
*/
package com.allenstudio.ir.util;
* @(#)xmlio.java
* created on 2005-8-12
*/
package com.allenstudio.ir.util;
import java.io.bufferedwriter;
import java.io.chararraywriter;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.io.outputstream;
import java.io.outputstreamwriter;
import java.io.writer;
import java.net.url;
import java.util.enumeration;
import java.util.iterator;
import java.util.list;
import java.util.vector;
import java.util.logging.logger;
import java.io.chararraywriter;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.io.outputstream;
import java.io.outputstreamwriter;
import java.io.writer;
import java.net.url;
import java.util.enumeration;
import java.util.iterator;
import java.util.list;
import java.util.vector;
import java.util.logging.logger;
import javax.swing.joptionpane;
import javax.xml.parsers.saxparser;
import javax.xml.parsers.saxparserfactory;
import javax.xml.parsers.saxparser;
import javax.xml.parsers.saxparserfactory;
import org.xml.sax.attributes;
import org.xml.sax.saxexception;
import org.xml.sax.xmlreader;
import org.xml.sax.helpers.defaulthandler;
import org.xml.sax.saxexception;
import org.xml.sax.xmlreader;
import org.xml.sax.helpers.defaulthandler;
/**
* xml io reading and writing utility.
*
* @author fdietz
*/
public class xmlio extends defaulthandler {
* xml io reading and writing utility.
*
* @author fdietz
*/
public class xmlio extends defaulthandler {
private static final logger log = logger.getlogger("org.columba.core.xml");
private static final string root_xml_element_name = "__inspirento_xml_tree_top__";
// list of sub-elements
@suppresswarnings("unused")
private list<xmlelement> elements;
@suppresswarnings("unused")
private list<xmlelement> elements;
// top level element (used to hold everything else)
private xmlelement rootelement;
private xmlelement rootelement;
// the current element you are working on
private xmlelement currentelement;
private xmlelement currentelement;
// for writing out the data
// indent for each level
private int writeindent = 2;
// indent for each level
private int writeindent = 2;
// maximum data to put on a "one liner"
private int maxonelinedata = 20;
private int maxonelinedata = 20;
// the sax 2 parser...
@suppresswarnings("unused")
private xmlreader xr;
@suppresswarnings("unused")
private xmlreader xr;
// buffer for collecting data from
// the "characters" sax event.
private chararraywriter contents = new chararraywriter();
private url url = null;
// the "characters" sax event.
private chararraywriter contents = new chararraywriter();
private url url = null;
/*
// default constructor
public xmlio() {
}
*/
/*
// setup and load constructor
public xmlio(string filepath) {
currentelement = null;
// default constructor
public xmlio() {
}
*/
/*
// setup and load constructor
public xmlio(string filepath) {
currentelement = null;
}
*/
public xmlio(url url) {
super();
this.url = url;
}
// setup and load constructor
public xmlio() {
currentelement = null;
}
public xmlio() {
currentelement = null;
}
// setup and load constructor
/**
* creates a xmlio object with the specified element at the top.
* @param element the element at the top.
*/
public xmlio(xmlelement element) {
rootelement = new xmlelement(root_xml_element_name);
rootelement.addelement(element);
}
* creates a xmlio object with the specified element at the top.
* @param element the element at the top.
*/
public xmlio(xmlelement element) {
rootelement = new xmlelement(root_xml_element_name);
rootelement.addelement(element);
}
public void seturl(url url) {
this.url = url;
}
this.url = url;
}
public boolean load() {
//this.file = f;
return load(url);
}
//this.file = f;
return load(url);
}
// load a file. this is what starts things off.
/**
* loads from the inputstream into the root xml element.
* @param input the input stream to load from.
*/
public boolean load(inputstream input) {
elements = new vector<xmlelement>();
rootelement = new xmlelement(root_xml_element_name);
currentelement = rootelement;
* loads from the inputstream into the root xml element.
* @param input the input stream to load from.
*/
public boolean load(inputstream input) {
elements = new vector<xmlelement>();
rootelement = new xmlelement(root_xml_element_name);
currentelement = rootelement;
try {
// create the xml reader...
// xr = xmlreaderfactory.createxmlreader();
saxparserfactory factory = saxparserfactory.newinstance();
// create the xml reader...
// xr = xmlreaderfactory.createxmlreader();
saxparserfactory factory = saxparserfactory.newinstance();
// set the contenthandler...
// xr.setcontenthandler( this );
saxparser saxparser = factory.newsaxparser();
// xr.setcontenthandler( this );
saxparser saxparser = factory.newsaxparser();
saxparser.parse(input, this);
} catch (javax.xml.parsers.parserconfigurationexception ex) {
log.severe("xml config error while attempting to read from the input stream \n" + input + "");
log.severe(ex.tostring());
ex.printstacktrace();
} catch (javax.xml.parsers.parserconfigurationexception ex) {
log.severe("xml config error while attempting to read from the input stream \n" + input + "");
log.severe(ex.tostring());
ex.printstacktrace();
return (false);
} catch (saxexception ex) {
// error
log.severe("xml parse error while attempting to read from the input stream \n" + input + "");
log.severe(ex.tostring());
ex.printstacktrace();
} catch (saxexception ex) {
// error
log.severe("xml parse error while attempting to read from the input stream \n" + input + "");
log.severe(ex.tostring());
ex.printstacktrace();
return (false);
} catch (ioexception ex) {
log.severe("i/o error while attempting to read from the input stream \n" + input + "");
log.severe(ex.tostring());
ex.printstacktrace();
} catch (ioexception ex) {
log.severe("i/o error while attempting to read from the input stream \n" + input + "");
log.severe(ex.tostring());
ex.printstacktrace();
return (false);
}
}
//xmlelement.printnode( getroot(), "");
return (true);
}
return (true);
}
/**
* load a file. this is what starts things off.
* @param inputurl the url to load xml from.
*/
public boolean load(url inputurl) {
elements = new vector<xmlelement>();
rootelement = new xmlelement(root_xml_element_name);
currentelement = rootelement;
* load a file. this is what starts things off.
* @param inputurl the url to load xml from.
*/
public boolean load(url inputurl) {
elements = new vector<xmlelement>();
rootelement = new xmlelement(root_xml_element_name);
currentelement = rootelement;
try {
// create the xml reader...
// xr = xmlreaderfactory.createxmlreader();
saxparserfactory factory = saxparserfactory.newinstance();
// create the xml reader...
// xr = xmlreaderfactory.createxmlreader();
saxparserfactory factory = saxparserfactory.newinstance();
// set the contenthandler...
// xr.setcontenthandler( this );
saxparser saxparser = factory.newsaxparser();
// xr.setcontenthandler( this );
saxparser saxparser = factory.newsaxparser();
saxparser.parse(inputurl.tostring(), this);
} catch (javax.xml.parsers.parserconfigurationexception ex) {
log.severe("xml config error while attempting to read xml file \n" + inputurl + "");
log.severe(ex.tostring());
ex.printstacktrace();
} catch (javax.xml.parsers.parserconfigurationexception ex) {
log.severe("xml config error while attempting to read xml file \n" + inputurl + "");
log.severe(ex.tostring());
ex.printstacktrace();
return (false);
} catch (saxexception ex) {
// error
log.severe("xml parse error while attempting to read xml file \n" + inputurl + "");
log.severe(ex.tostring());
ex.printstacktrace();
} catch (saxexception ex) {
// error
log.severe("xml parse error while attempting to read xml file \n" + inputurl + "");
log.severe(ex.tostring());
ex.printstacktrace();
return (false);
} catch (ioexception ex) {
log.severe("i/o error while attempting to read xml file \n" + inputurl + "");
log.severe(ex.tostring());
ex.printstacktrace();
} catch (ioexception ex) {
log.severe("i/o error while attempting to read xml file \n" + inputurl + "");
log.severe(ex.tostring());
ex.printstacktrace();
return (false);
}
}
//xmlelement.printnode( getroot(), "");
return (true);
}
return (true);
}
// implement the content hander methods that
// will delegate sax events to the tag tracker network.
@override
public void startelement(string namespaceuri, string localname,
string qname, attributes attrs) throws saxexception {
// resetting contents buffer.
// assuming that tags either tag content or children, not both.
// this is usually the case with xml that is representing
// data strucutures in a programming language independant way.
// this assumption is not typically valid where xml is being
// used in the classical text mark up style where tagging
// is used to style content and several styles may overlap
// at once.
try {
contents.reset();
// will delegate sax events to the tag tracker network.
@override
public void startelement(string namespaceuri, string localname,
string qname, attributes attrs) throws saxexception {
// resetting contents buffer.
// assuming that tags either tag content or children, not both.
// this is usually the case with xml that is representing
// data strucutures in a programming language independant way.
// this assumption is not typically valid where xml is being
// used in the classical text mark up style where tagging
// is used to style content and several styles may overlap
// at once.
try {
contents.reset();
string name = localname; // element name
if (name.equals("")) {
name = qname; // namespaceaware = false
}
name = qname; // namespaceaware = false
}
xmlelement p = currentelement;
currentelement = currentelement.addsubelement(name);
currentelement.setparent(p);
currentelement.setparent(p);
if (attrs != null) {
for (int i = 0; i < attrs.getlength(); i++) {
string aname = attrs.getlocalname(i); // attr name
for (int i = 0; i < attrs.getlength(); i++) {
string aname = attrs.getlocalname(i); // attr name
if (aname.equals("")) {
aname = attrs.getqname(i);
}
aname = attrs.getqname(i);
}
currentelement.addattribute(aname, attrs.getvalue(i));
}
}
} catch (java.lang.nullpointerexception ex) {
log.severe("null!!!");
log.severe(ex.tostring());
ex.printstacktrace();
}
}
}
}
} catch (java.lang.nullpointerexception ex) {
log.severe("null!!!");
log.severe(ex.tostring());
ex.printstacktrace();
}
}
@override
public void endelement(string namespaceuri, string localname, string qname)
throws saxexception {
currentelement.setdata(contents.tostring().trim());
contents.reset();
public void endelement(string namespaceuri, string localname, string qname)
throws saxexception {
currentelement.setdata(contents.tostring().trim());
contents.reset();
currentelement = currentelement.getparent();
}
}
@override
public void characters(char[] ch, int start, int length)
throws saxexception {
// accumulate the contents into a buffer.
contents.write(ch, start, length);
}
public void characters(char[] ch, int start, int length)
throws saxexception {
// accumulate the contents into a buffer.
contents.write(ch, start, length);
}
/**
* returns the root for the xmlelement hiearchy.
* note that this xml element will always have the name <code>__columba_xml_tree_top__</code>.
* <p>
* methods that want to retrieve elements from this root should use
* the {@link xmlelement#getelement(string)} in order to get the wanted
* element.
* @return a xmlelement if it has been loaded or initialized with it; null otherwise.
*/
public xmlelement getroot() {
return (rootelement);
}
* returns the root for the xmlelement hiearchy.
* note that this xml element will always have the name <code>__columba_xml_tree_top__</code>.
* <p>
* methods that want to retrieve elements from this root should use
* the {@link xmlelement#getelement(string)} in order to get the wanted
* element.
* @return a xmlelement if it has been loaded or initialized with it; null otherwise.
*/
public xmlelement getroot() {
return (rootelement);
}
public void errordialog(string msg) {
joptionpane.showmessagedialog(null, "error: " + msg);
}
joptionpane.showmessagedialog(null, "error: " + msg);
}
public void warningdialog(string msg) {
joptionpane.showmessagedialog(null, "warning: " + msg);
}
joptionpane.showmessagedialog(null, "warning: " + msg);
}
public void infodialog(string msg) {
joptionpane.showmessagedialog(null, "info: " + msg);
}
joptionpane.showmessagedialog(null, "info: " + msg);
}
public void save() throws exception {
write(new fileoutputstream(url.getpath()));
}
write(new fileoutputstream(url.getpath()));
}
//
// writer interface
//
public void write(outputstream out) throws ioexception {
bufferedwriter pw = new bufferedwriter(new outputstreamwriter(out,
"utf-8"));
pw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
// writer interface
//
public void write(outputstream out) throws ioexception {
bufferedwriter pw = new bufferedwriter(new outputstreamwriter(out,
"utf-8"));
pw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
if (rootelement.subelements.size() > 0) {
for (int i = 0; i < rootelement.subelements.size(); i++) {
_writesubnode(pw, (xmlelement) rootelement.subelements.get(i), 0);
}
}
for (int i = 0; i < rootelement.subelements.size(); i++) {
_writesubnode(pw, (xmlelement) rootelement.subelements.get(i), 0);
}
}
pw.flush();
}
}
private void _writesubnode(writer out, xmlelement element, int indent)
throws ioexception {
_writespace(out, indent);
out.write("<");
out.write(element.getname());
throws ioexception {
_writespace(out, indent);
out.write("<");
out.write(element.getname());
for (enumeration e = element.getattributenames(); e.hasmoreelements();) {
string k = (string) e.nextelement();
out.write(" " + k + "=\"" + inspirentoutilities.escapetext(element.getattribute(k)) + "\"");
}
string k = (string) e.nextelement();
out.write(" " + k + "=\"" + inspirentoutilities.escapetext(element.getattribute(k)) + "\"");
}
out.write(">");
string data = element.getdata();
if ((data != null) && !data.equals("")) {
if (data.length() > maxonelinedata) {
out.write("\n");
_writespace(out, indent + writeindent);
}
if (data.length() > maxonelinedata) {
out.write("\n");
_writespace(out, indent + writeindent);
}
out.write(inspirentoutilities.escapetext(data));
}
}
list subelements = element.getelements();
if (subelements.size() > 0) {
out.write("\n");
out.write("\n");
for (iterator it = subelements.iterator(); it.hasnext();) {
_writesubnode(out, (xmlelement) it.next(), indent + writeindent);
_writesubnode(out, (xmlelement) it.next(), indent + writeindent);
// for (int i = 0; i < subelements.size(); i++) {
// _writesubnode(
// out,
// (xmlelement) subelements.get(i),
// indent + writeindent);
}
// _writesubnode(
// out,
// (xmlelement) subelements.get(i),
// indent + writeindent);
}
_writespace(out, indent);
}
}
if (data.length() > maxonelinedata) {
out.write("\n");
_writespace(out, indent);
}
out.write("\n");
_writespace(out, indent);
}
out.write("</" + inspirentoutilities.escapetext(element.getname()) + ">\n");
}
}
private void _writespace(writer out, int numspaces)
throws ioexception {
for (int i = 0; i < numspaces; i++) {
out.write(" ");
}
}
}
throws ioexception {
for (int i = 0; i < numspaces; i++) {
out.write(" ");
}
}
}
下面是继承properties的configurationmanager,其中的getproperty和setproperty方法已经被overridden。
/*
* @(#)configurationmanager.java
* created on 2005-8-10
*/
package com.allenstudio.ir.core;
* @(#)configurationmanager.java
* created on 2005-8-10
*/
package com.allenstudio.ir.core;
import java.util.*;
import java.io.*;
import java.io.*;
import com.allenstudio.ir.util.*;
/**
* manages the configuration for inspirento.<br>
* this manager uses xml format to store information.
* the configuration file is, by default, saved in the
* "config" directory and named "config.xml". clearly,
* this class should be a singleton, so we use
* {@link #getinstance()} to get an instance and call
* other instance methods to get the settings needed
* by inspirento, such as "windowsize", "windowlocation",
* and etc.<br>
* the program first tries to get the configuration from
* this <code>configurationmanager</code>. if it fails to
* get any key, it uses the default settings presetted in
* the protected <code>default</code> field.
*
* @author allen chue
*/
public class configurationmanager extends properties {
public static final string config_directory = "config";
public static final string config_file = "config.xml";
public static final string common_prefix = "inspirento.";
private static configurationmanager instance = null;
private xmlio xmlio;
/**
* private constructor for singleton use.
*/
private configurationmanager() {
initdefaultsettings();
readin();
}
public static configurationmanager getinstance() {
if (instance != null) {
return instance;
} else {
instance = new configurationmanager();
return instance;
}
}
public void readin() {
try {
file configfile = new file(
config_directory +
system.getproperty("file.separator") +
config_file);//$non-nls-1$
if (configfile.exists()) {
fileinputstream configstream = new fileinputstream(configfile);
xmlio = new xmlio();
xmlio.load(configstream);
configstream.close();
}
} catch (exception e) {
system.out.println("cannot load configuration file" +
" supposed to be at \"config\\config.xml\"" +
"\ndefault settings will be stored as the replacement.");//$non-nls-1$
writedefaultstofile();
e.printstacktrace();
}
}
public void writeback() {
try {
fileoutputstream configfile = new fileoutputstream(
config_directory +
system.getproperty("file.separator") +
config_file);
xmlio.write(configfile);
configfile.close();
} catch (exception e) {
system.out.println("cannot write configuration file" +
" to \"config\\config.xml\"");//$non-nls-1$
e.printstacktrace();
}
}
/**
* uses xml parser to get the specified property.
* if there is no such a key, the method returns
* <code>null</code>.
* @param key the key of the property
* @return the property value
*/
@override
public synchronized string getproperty(string key) {
string value = xmlio.getroot().getelement(constants.project_name +
"." + getpath(key)[0]).getattribute(getpath(key)[1]);
if (value == null) {//perhaps some element is lost in the file
value = defaults.getproperty(key);
setproperty(key, value);//null value has no side effect
new thread(){
@override
public void run() {
writeback();
}
}.start();
}
return value;
}
@override
public synchronized object setproperty(string key, string value) {
xmlio.getroot().getelement(constants.project_name +
"." + getpath(key)[0]).addattribute(getpath(key)[1], value);
return value;
}
/**
* when the configuration file is lost, this method
* is used to write the default settings stored in
* the program itself to file.
*
*/
private void writedefaultstofile() {
enumeration keys = defaults.keys();
xmlelement xe = new xmlelement(constants.project_name);
xmlio = new xmlio(xe);
for (; keys.hasmoreelements(); ) {
string pathtext = (string)keys.nextelement();
* manages the configuration for inspirento.<br>
* this manager uses xml format to store information.
* the configuration file is, by default, saved in the
* "config" directory and named "config.xml". clearly,
* this class should be a singleton, so we use
* {@link #getinstance()} to get an instance and call
* other instance methods to get the settings needed
* by inspirento, such as "windowsize", "windowlocation",
* and etc.<br>
* the program first tries to get the configuration from
* this <code>configurationmanager</code>. if it fails to
* get any key, it uses the default settings presetted in
* the protected <code>default</code> field.
*
* @author allen chue
*/
public class configurationmanager extends properties {
public static final string config_directory = "config";
public static final string config_file = "config.xml";
public static final string common_prefix = "inspirento.";
private static configurationmanager instance = null;
private xmlio xmlio;
/**
* private constructor for singleton use.
*/
private configurationmanager() {
initdefaultsettings();
readin();
}
public static configurationmanager getinstance() {
if (instance != null) {
return instance;
} else {
instance = new configurationmanager();
return instance;
}
}
public void readin() {
try {
file configfile = new file(
config_directory +
system.getproperty("file.separator") +
config_file);//$non-nls-1$
if (configfile.exists()) {
fileinputstream configstream = new fileinputstream(configfile);
xmlio = new xmlio();
xmlio.load(configstream);
configstream.close();
}
} catch (exception e) {
system.out.println("cannot load configuration file" +
" supposed to be at \"config\\config.xml\"" +
"\ndefault settings will be stored as the replacement.");//$non-nls-1$
writedefaultstofile();
e.printstacktrace();
}
}
public void writeback() {
try {
fileoutputstream configfile = new fileoutputstream(
config_directory +
system.getproperty("file.separator") +
config_file);
xmlio.write(configfile);
configfile.close();
} catch (exception e) {
system.out.println("cannot write configuration file" +
" to \"config\\config.xml\"");//$non-nls-1$
e.printstacktrace();
}
}
/**
* uses xml parser to get the specified property.
* if there is no such a key, the method returns
* <code>null</code>.
* @param key the key of the property
* @return the property value
*/
@override
public synchronized string getproperty(string key) {
string value = xmlio.getroot().getelement(constants.project_name +
"." + getpath(key)[0]).getattribute(getpath(key)[1]);
if (value == null) {//perhaps some element is lost in the file
value = defaults.getproperty(key);
setproperty(key, value);//null value has no side effect
new thread(){
@override
public void run() {
writeback();
}
}.start();
}
return value;
}
@override
public synchronized object setproperty(string key, string value) {
xmlio.getroot().getelement(constants.project_name +
"." + getpath(key)[0]).addattribute(getpath(key)[1], value);
return value;
}
/**
* when the configuration file is lost, this method
* is used to write the default settings stored in
* the program itself to file.
*
*/
private void writedefaultstofile() {
enumeration keys = defaults.keys();
xmlelement xe = new xmlelement(constants.project_name);
xmlio = new xmlio(xe);
for (; keys.hasmoreelements(); ) {
string pathtext = (string)keys.nextelement();
string[] path = getpath(pathtext);
//test if the element to be modified exists
xmlelement elementadded = xe.getelement(path[0]);
if (elementadded == null){
elementadded = xe.addsubelement(path[0]);
}
elementadded.addattribute(path[1], defaults.getproperty(pathtext));
}
try {
fileoutputstream configfile = new fileoutputstream(
config_directory +
system.getproperty("file.separator") +
config_file);//$non-nls-1$
xmlio.write(configfile);
configfile.close();
} catch (exception e) {
system.out.println("cannot write configuration file" +
" to \"config\\config.xml\"");//$non-nls-1$
e.printstacktrace();
}
}
/**
* returns an string array of length 2.
* the parameter <code>pathtext</code> is supposed to
* be a string separated with dots. for example,
* "inspirento.window.location" is a valid parameter.
* this method puts the token after the last dot in
* the second position of the result array, and the
* remaining string(excluding the last dot) in the first
* position of the result array. it is a rivate helping method.
* <br>
* example: getpath("inspirento.window.location") returns
* the array {"inspirento.window", "location"}.<br>
* <em>no format checking is done in this method! <code>
* arrayoutofboundsexception</code> will be thrown
* when no dots are found in the string.</em>
* @param pathtext the path text to be processed
* @return an array containing the result
*/
private static string[] getpath(string pathtext) {
int dotpos = pathtext.lastindexof(.);
string[] result = new string[2];
result[0] = pathtext.substring(0, dotpos);
result[1] = pathtext.substring(dotpos + 1);
return result;
}
private void initdefaultsettings() {
string[] configdefaults = {
"window.location", "400,300",
"window.size", "450,300"
};
defaults = new properties();
for(int i = 0, max = configdefaults.length; i < max; i += 2) {
string value = configdefaults[i + 1];
defaults.setproperty(configdefaults[i], value);
}
}
}
//test if the element to be modified exists
xmlelement elementadded = xe.getelement(path[0]);
if (elementadded == null){
elementadded = xe.addsubelement(path[0]);
}
elementadded.addattribute(path[1], defaults.getproperty(pathtext));
}
try {
fileoutputstream configfile = new fileoutputstream(
config_directory +
system.getproperty("file.separator") +
config_file);//$non-nls-1$
xmlio.write(configfile);
configfile.close();
} catch (exception e) {
system.out.println("cannot write configuration file" +
" to \"config\\config.xml\"");//$non-nls-1$
e.printstacktrace();
}
}
/**
* returns an string array of length 2.
* the parameter <code>pathtext</code> is supposed to
* be a string separated with dots. for example,
* "inspirento.window.location" is a valid parameter.
* this method puts the token after the last dot in
* the second position of the result array, and the
* remaining string(excluding the last dot) in the first
* position of the result array. it is a rivate helping method.
* <br>
* example: getpath("inspirento.window.location") returns
* the array {"inspirento.window", "location"}.<br>
* <em>no format checking is done in this method! <code>
* arrayoutofboundsexception</code> will be thrown
* when no dots are found in the string.</em>
* @param pathtext the path text to be processed
* @return an array containing the result
*/
private static string[] getpath(string pathtext) {
int dotpos = pathtext.lastindexof(.);
string[] result = new string[2];
result[0] = pathtext.substring(0, dotpos);
result[1] = pathtext.substring(dotpos + 1);
return result;
}
private void initdefaultsettings() {
string[] configdefaults = {
"window.location", "400,300",
"window.size", "450,300"
};
defaults = new properties();
for(int i = 0, max = configdefaults.length; i < max; i += 2) {
string value = configdefaults[i + 1];
defaults.setproperty(configdefaults[i], value);
}
}
}
在上面的代码中,inspirento是我的项目,可以根据情况修改。实际这个类是使用在整个程序的配置获取和修改的。如果用它处理前面的属性,可以得到这样的文件,可以看到它有层次感,更便于处理和阅读。
<?xml version="1.0" encoding="utf-8"?>
<inspirento>
<window location="202 ,179" size="532 ,455"></window>
</inspirento>
<inspirento>
<window location="202 ,179" size="532 ,455"></window>
</inspirento>
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!


