XML 包概述。

术语

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);
		}
	}