用語
コーデック (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);
}
}