XML パッケージの概要。

用語

コーデック (codec) coder/decoder の省略名 ターミナルノード <tag>内容</tag> 形式の XML ノード

目標

R1 XML 記述ユーティリティー。 SAX は構文解析を行います。ただし、インデント設定、属性、エスケープ、および XML ドキュメントのヘッダーとフッターに 役立つユーティリティーはありません。 R2 実際のオブジェクトから分離させたコーデック。 代替方法として、シリアライズ可能なオブジェクトを使用して、特定のコーデックインタフェースを実装する方法があります。 コーデックの分離には、次の利点があります。 - 変更できないクラスのためのコーデックを作成できます。 - 一般に、デコードはクラスの拡張時に役立ちます。ただし、デコーダクラスの拡張は、オブジェクトクラスの既存の継承と 衝突する場合があります。 インタフェースを利用して、委託先の「サポート」クラスを作成することもできますが、それではますます不便になります。 R3 ドキュメントへの関連付けを持たないコーデック。 最上位に <breakpoints> を含む XML ドキュメントがある場合があります。 将来、その <breakpoints> を、別のドキュメントの <profile> の一部として埋め込む可能性があります。 <breakpoints> のコーデックでは、<breakpoints> がドキュメント内に存在するかどうか、また、どこに <breakpoints> が 埋め込まれているかについて、識別しておく必要はありません。 R4 単一のコーデッククラス。 エンコード用とデコード用に、クラスをそれぞれ作成する必要がありません。 これにより、すべての XML 固有のコーデック (主にタグや属性の名前) を、1 つのクラスに情報としてカプセル化できるように なります。 R* ドライバオブジェクト構造のためのタグ [暫定]

動機の経緯

- SunStudio の開発中、収集データの格納場所をよく移動し (メモリーと持続性の両方)、異なる XML 持続性構造へ適応させること は、1 つの PIB であることに気付きました。 ここから、R3 の目標が生まれました。 - cnd makeproject では、サブシステムの構文解析および作成を、すばやく処理するという概念を、ConfigurationAuxObject と 呼ばれるインタフェースを使用したサブシステムに導入しました。しかし、この仕組みは ConfigurationDescriptorHelper に ハードコーディングされているため、そこからメリットは得られませんでした。 この実装は R3 の解決法として最初に得られたものであり、このパッケージで一般化します。 - 特に XML を書き出すというような、大量のコピー&ペーストコードによって、次に示すようなさまざま特長が失われます。 - 適切な XML エンコーディング属性 (「UTF-8」以外が必要になることがある)。 - 一貫性のない引用。XMLUtil.toAttributeValue を使用した属性値の引用が、一部の場所でのみ使用されたり、 XMLUtil.toElementContent による内容コーディングが、全く使用されなかったりしました。 - 大量のコードが、XML 文字列をほかの場所に渡す前に、XML 文字列への変換に依存していました。コーデックがストリームに 書き込む方が効率的です。

次の例では、定義が空のメソッドは取り除かれています。これは簡潔にするためであり、実際のコードでは、定義が空のメソッドも
実装してインタフェースを満たす必要があります。 次のように格納されるデータについて検討してみましょう。
	<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);	// デフォルトの 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);
		}


		// インタフェース XMLEncoder
		public void encode(XMLEncoderStream xes) {
			codec.encode(xes);
		}
	}

	FamilyXMLCodec extends XMLDecoder implements XMLEncoder {

		private Family family		// 書き出し
		private PersonXMLCodec personCodec;
		private ChildrenXMLCodec childrenCodec;

		FamilyXMLCodec(Family family) {
			this.family = family;
			personCodec = new PersonXMLCodec();
			childrenCodec = new ChildrenXMLCodec(family.children);
		}

		// インタフェース XMLDecoder
		protected String tag() {
			return "family"
		}

		// インタフェース 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();
		}

		// インタフェース XMLDecoder
		protected String tag() {
			return "children"
		}

		// インタフェース 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;
		}

		// インタフェース XMLDecoder
		protected String tag() {
			return "person"
		}

		// インタフェース 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);
		}

		// インタフェース XMLDecoder
		protected String tag() {
			return "family"
		}

		// インタフェース XMLDecoder
		protected void startElement(String name, Attributes atts) {

			// 前述の登録処理で  が表示されると、
// personCode.start() が自動的に呼びされる // ここでは単に、適切な Person インスタンスに
// デコードする 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 } } /** * children のデコードには、前処理が必要です。 * 新しい Person を書き込むコンテナ (Vector) を受け付ける
* PersonXMLCodec のバージョンをインスタンス化して、登録しています。 */ 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; } /** * setPerson() までデコード先の person の設定を遅らせるときに
* 使用するフォーム。 */ PersonXMLCodec(Person person { this.person = null; } /** * Person を作成して、デコードし、「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); } }