术语
codec 编码器/解码器 (Coder/Decoder) 的缩写 终端节点 采用以下方式表示的 XML 节点 <tag>内容</tag>目标
R1 XML 编写实用程序。 除了 SAX 能够解析以外,没有其他实用程序能够处理缩排、属性、转义 以及 XML 文档的标题和脚注。 R2 codec 与实际对象相分离。 替代方案将使用可序列化的对象来实现特定的 codec 接口。 使用单独的 codec 具有如下优点: - 允许我们为无法修改的类编写 codec。 - 解码通常会从类扩展中受益。但扩展解码器类可能会与对象类的现有继承 发生冲突。 当然了,人们可以使用接口并随后创建要委托的“支持”类,但这会变得 越来越不方便。 R3 codec 与文档没有关联。 假设某一 XML 文档在顶层包含了 <断点>,某一天,我们要将 <断点> 作为 <配置文件> 的一部分嵌入到另一个文档中。则 <断点> codec 无需知道它是 否位于文档中,或者它被嵌入在何处。 R4 单个 codec 类 不需要单独编写一个编码类和一个解码类,您可以将所有特定于 XML 的编码 和解码信息(主要是标记和属性名称)封装在一个类中。 R* 表示用于驱动程序对象构造的标记 [暂定]历史原因
- 在开发 Sun Studio 时,我们发现经常需要迁移数据集合的存储目录(在 内存和持久性基础结构中),但针对不同的 XML 持久性基础结构所做的修改 工作是非常大的。为此,我们定制了 R3 目标。 - cnd makeproject 引入了通过所谓的 ConfigurationAuxObject 接口将子系统 的解析和编写分发到子系统的概念。但是,此机制已在 ConfigurationDescriptorHelper 中进行了固定编码,因此其他人无法从中获益。 该实现是 R3 的第一个近似解决方案,我们在此包中对其进行了泛化处理。 - 特别是在编写 XML 时,进行大量的代码复制粘贴操作会降低各种功能的 性能: - 相应的 XML 编码属性(有时,它需要的不是 "UTF-8")。 - 不一致的引用。通过 XMLUtil.toAttributeValue 实现的属性值引用仅在 某些地方使用。通过 XMLUtil.toElementContent 实现的内容编码并不是在 所有地方都使用。 - 很多代码在传递到其他位置之前,需要转换为 XML 字符串。如果 codec 只写入到流,则会更有效。
<family> <father> <person firstName="X" lastName="L" gender="M"/> </father> <mother> <person firstName="Y" lastName="L" gender="F"/> </mother> <children> <person firstName="Z" lastName="L" gender="M"/> </children> </family>它基于
class Family {
Person mother;
Person father;
Vector<Person> children;
}
让我们了解一下如何编写此代码。
FamilyXMLDocWriter writer = new FamilyXMLDocWriter(family);
writer.setIndentChars(4); // as opposed to default of 2
writer.write(new File("family.html");
FamilyXMLDocWriter extends XMLDocWriter {
FamilyXMLCodec codec;
FamilyXMLDocWriter(Family family) {
codec = new FamilyXMLCodec(family);
}
public void write(File file) {
OutputStream os = file.();
write(os);
}
// interface XMLEncoder
public void encode(XMLEncoderStream xes) {
codec.encode(xes);
}
}
FamilyXMLCodec extends XMLDecoder implements XMLEncoder {
private Family family // being written out
private PersonXMLCodec personCodec;
private ChildrenXMLCodec childrenCodec;
FamilyXMLCodec(Family family) {
this.family = family;
personCodec = new PersonXMLCodec();
childrenCodec = new ChildrenXMLCodec(family.children);
}
// interface XMLDecoder
protected String tag() {
return "family"
}
// interface XMLEncoder
public void encode(XMLEncoderStream xes) {
xes.elementOpen(tag());
xes.elementOpen("father");
personCodec.setPerson(father);
personCodec.encode(xes)
xes.elementClose("father");
xes.elementOpen("mother");
personCodec.setPerson(mother);
personCodec.encode(xes)
xes.elementClose("mother");
childrenCodec.encode(xes);
xes.elementClose(tag());
}
}
ChildrenXMLCodec extends XMLDecoder implements XMLEncoder {
private Vector<PErson> children;
private PersonXMLCodec personCodec;
ChildrenXMLCodec(Vector<Person> children) {
this.children = children;
personCodec = new PersonXMLCodec();
}
// interface XMLDecoder
protected String tag() {
return "children"
}
// interface XMLEncoder
public void encode(XMLEncoderStream xes) {
xes.elementOpen(tag());
for (Person p in children) {
personCodec.setPerson(p);
personCodec.encode(xes);
}
xes.elementClose(tag());
}
}
PersonXMLCodec extends XMLDecoder implements XMLEncoder {
private Person person;
private Vector<Person> list;
PersonXMLCodec(Person person {
this.person = person;
}
PersonXMLCodec(Vector<Person> list) {
this.list = list;
}
public void setPerson(Person person) {
this.person = person;
}
// interface XMLDecoder
protected String tag() {
return "person"
}
// interface XMLEncoder
public void encode(XMLEncoderStream xes) {
AttrValuePair attrs[] = new AttrValuePair[] {
new AttrValuePair("firstName",
person.firstName);
new AttrValuePair("lastName",
person.lastName);
new AttrValuePair("gender",
person.gender);
}
xes.element(tag(), attrs);
}
}
现在,让我们了解一下如何读取这些代码。
下面的类与上面的类相同,但删除了与编码有关的代码,而只显示用于解码的代码。
FamilyXMLDocReader writer = new FamilyXMLDocReader(family);
writer.write(new File("family.html");
FamilyXMLDocReader extends XMLDocReader {
FamilyXMLCodec codec;
FamilyXMLDocReader(Family family) {
codec = new FamilyXMLCodec(family);
registerXMLDecoder(codec);
}
public void write(File file) {
InputStream is = file.();
String what = "family"
read(is, what);
}
}
FamilyXMLCodec extends XMLDecoder implements XMLEncoder {
private Family family
private PersonXMLCodec personCodec;
private ChildrenXMLCodec childrenCodec;
FamilyXMLCodec(Family family) {
this.family = family;
personCodec = new PersonXMLCodec();
registerXMLEncoder(personCodec);
childrenCodec = new ChildrenXMLCodec(family.children);
registerXMLEncoder(childrenCodec);
}
// interface XMLDecoder
protected String tag() {
return "family"
}
// interface XMLDecoder
protected void startElement(String name, Attributes atts) {
// personCode.start() will automatically be called when
// is seen due to the above registration.
// Here we just ensure that we decode into the
// right Person instance
if (name.equals("mother")) {
family.mother = new Person();
personCodec.setPerson(family.mother);
}
else if (name.equals("father")) {
family.father = new Person();
personCodec.setPerson(family.father);
}
// children handled by registration
}
}
/**
* For decosing children we cheat a bit.
* We instantiate and register a version of PersonXMLCodec which
* takes a container (Vector) to stuff new Persons into.
*/
ChildrenXMLCodec extends XMLDecoder implements XMLEncoder {
private Vector<PErson> children;
private PersonXMLCodec personCodec;
ChildrenXMLCodec(Vector<Person> children) {
this.children = children;
personCodec = new PersonXMLCodec(children);
registerXMLEncoder(personCodec);
}
// interface XMLDecoder
protected String tag() {
return "children"
}
}
PersonXMLCodec extends XMLDecoder implements XMLEncoder {
private Person person;
private Vector<Person> list;
PersonXMLCodec(Person person {
this.person = person;
}
/**
* Form used when we delay setting the person to be decoded
* into til setPerson().
*/
PersonXMLCodec(Person person {
this.person = null;
}
/**
* Form used when we create Persons, decode them and add them
* to 'list'
*/
PersonXMLCodec(Vector<Person> list) {
this.list = list;
}
public void setPerson(Person person) {
this.person = person;
}
// interface XMLDecoder
protected String tag() {
return "person"
}
// interface XMLDecoder
protected void start(Attributes atts) {
Person newPerson = person;
if (!newPerson)
newPerson = new Person();
person.firstName = atts.getValue("firstName");
person.familyName = atts.getValue("familyName");
person.gender = atts.getValue("gender");
if (list != null)
list.add(newPerson);
}
}