1f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling//=================================================================================================
2f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ADOBE SYSTEMS INCORPORATED
3f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// Copyright 2006 Adobe Systems Incorporated
4f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// All Rights Reserved
5f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling//
6f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
7f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// of the Adobe license agreement accompanying it.
8f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// =================================================================================================
9f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
10f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpackage com.adobe.xmp.impl;
11f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
12f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.ArrayList;
13f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Arrays;
14f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Collections;
15f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Iterator;
16f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.List;
17f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.ListIterator;
18f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
19f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPConst;
20f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPError;
21f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPException;
22f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.options.PropertyOptions;
23f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
24f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
25f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling/**
26f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * A node in the internally XMP tree, which can be a schema node, a property node, an array node,
27f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * an array item, a struct node or a qualifier node (without '?').
28f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling *
29f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Possible improvements:
30f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling *
31f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 1. The kind Node of node might be better represented by a class-hierarchy of different nodes.
32f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 2. The array type should be an enum
33f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 3. isImplicitNode should be removed completely and replaced by return values of fi.
34f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 4. hasLanguage, hasType should be automatically maintained by XMPNode
35f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling *
36f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @since 21.02.2006
37f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */
38f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingclass XMPNode implements Comparable
39f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling{
40f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** name of the node, contains different information depending of the node kind */
41f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private String name;
42f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** value of the node, contains different information depending of the node kind */
43f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private String value;
44f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** link to the parent node */
45f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private XMPNode parent;
46f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** list of child nodes, lazy initialized */
47f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private List children = null;
48f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** list of qualifier of the node, lazy initialized */
49f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private List qualifier = null;
50f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** options describing the kind of the node */
51f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private PropertyOptions options = null;
52f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
53f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	// internal processing options
54f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
55f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** flag if the node is implicitly created */
56f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private boolean implicit;
57f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** flag if the node has aliases */
58f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private boolean hasAliases;
59f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** flag if the node is an alias */
60f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private boolean alias;
61f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/** flag if the node has an "rdf:value" child node. */
62f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private boolean hasValueChild;
63f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
64f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
65f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
66f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
67f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Creates an <code>XMPNode</code> with initial values.
68f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
69f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param name the name of the node
70f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param value the value of the node
71f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param options the options of the node
72f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
73f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode(String name, String value, PropertyOptions options)
74f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
75f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.name = name;
76f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.value = value;
77f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.options = options;
78f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
79f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
80f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
81f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
82f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Constructor for the node without value.
83f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
84f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param name the name of the node
85f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param options the options of the node
86f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
87f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode(String name, PropertyOptions options)
88f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
89f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this(name, null, options);
90f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
91f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
92f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
93f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
94f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Resets the node.
95f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
96f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void clear()
97f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
98f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		options = null;
99f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		name = null;
100f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		value = null;
101f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		children = null;
102f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		qualifier = null;
103f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
104f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
105f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
106f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
107f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the parent node.
108f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
109f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode getParent()
110f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
111f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return parent;
112f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
113f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
114f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
115f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
116f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param index an index [1..size]
117f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the child with the requested index.
118f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
119f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode getChild(int index)
120f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
121f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return (XMPNode) getChildren().get(index - 1);
122f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
123f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
124f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
125f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
126f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Adds a node as child to this node.
127f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param node an XMPNode
128f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @throws XMPException
129f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
130f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void addChild(XMPNode node) throws XMPException
131f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
132f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// check for duplicate properties
133f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		assertChildNotExisting(node.getName());
134f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		node.setParent(this);
135f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getChildren().add(node);
136f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
137f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
138f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
139f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
140f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Adds a node as child to this node.
141f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param index the index of the node <em>before</em> which the new one is inserted.
142f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <em>Note:</em> The node children are indexed from [1..size]!
143f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * An index of size + 1 appends a node.
144f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param node an XMPNode
145f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @throws XMPException
146f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
147f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void addChild(int index, XMPNode node) throws XMPException
148f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
149f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		assertChildNotExisting(node.getName());
150f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		node.setParent(this);
151f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getChildren().add(index - 1, node);
152f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
153f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
154f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
155f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
156f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Replaces a node with another one.
157f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param index the index of the node that will be replaced.
158f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <em>Note:</em> The node children are indexed from [1..size]!
159f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param node the replacement XMPNode
160f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
161f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void replaceChild(int index, XMPNode node)
162f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
163f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		node.setParent(this);
164f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getChildren().set(index - 1, node);
165f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
166f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
167f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
168f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
169f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Removes a child at the requested index.
170f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param itemIndex the index to remove [1..size]
171f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
172f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void removeChild(int itemIndex)
173f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
174f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getChildren().remove(itemIndex - 1);
175f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		cleanupChildren();
176f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
177f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
178f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
179f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
180f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Removes a child node.
181f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * If its a schema node and doesn't have any children anymore, its deleted.
182f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
183f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param node the child node to delete.
184f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
185f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void removeChild(XMPNode node)
186f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
187f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getChildren().remove(node);
188f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		cleanupChildren();
189f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
190f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
191f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
192f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
193f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Removes the children list if this node has no children anymore;
194f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * checks if the provided node is a schema node and doesn't have any children anymore,
195f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * its deleted.
196f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
197f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	protected void cleanupChildren()
198f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
199f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (children.isEmpty())
200f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
201f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			children = null;
202f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
203f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
204f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
205f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
206f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
207f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Removes all children from the node.
208f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
209f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void removeChildren()
210f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
211f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		children = null;
212f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
213f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
214f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
215f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
216f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the number of children without neccessarily creating a list.
217f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
218f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public int getChildrenLength()
219f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
220f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return children != null ?
221f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			children.size() :
222f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			0;
223f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
224f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
225f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
226f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
227f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param expr child node name to look for
228f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns an <code>XMPNode</code> if node has been found, <code>null</code> otherwise.
229f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
230f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode findChildByName(String expr)
231f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
232f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return find(getChildren(), expr);
233f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
234f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
235f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
236f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
237f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param index an index [1..size]
238f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the qualifier with the requested index.
239f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
240f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode getQualifier(int index)
241f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
242f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return (XMPNode) getQualifier().get(index - 1);
243f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
244f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
245f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
246f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
247f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the number of qualifier without neccessarily creating a list.
248f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
249f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public int getQualifierLength()
250f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
251f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return qualifier != null ?
252f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			qualifier.size() :
253f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			0;
254f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
255f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
256f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
257f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
258f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Appends a qualifier to the qualifier list and sets respective options.
259f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param qualNode a qualifier node.
260f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @throws XMPException
261f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
262f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void addQualifier(XMPNode qualNode) throws XMPException
263f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
264f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		assertQualifierNotExisting(qualNode.getName());
265f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		qualNode.setParent(this);
266f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		qualNode.getOptions().setQualifier(true);
267f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getOptions().setHasQualifiers(true);
268f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
269f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// contraints
270f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (qualNode.isLanguageNode())
271f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
272f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// "xml:lang" is always first and the option "hasLanguage" is set
273f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			options.setHasLanguage(true);
274f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			getQualifier().add(0, qualNode);
275f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
276f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else if (qualNode.isTypeNode())
277f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
278f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// "rdf:type" must be first or second after "xml:lang" and the option "hasType" is set
279f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			options.setHasType(true);
280f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			getQualifier().add(
281f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				!options.getHasLanguage() ? 0 : 1,
282f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				qualNode);
283f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
284f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else
285f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
286f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// other qualifiers are appended
287f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			getQualifier().add(qualNode);
288f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
289f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
290f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
291f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
292f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
293f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Removes one qualifier node and fixes the options.
294f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param qualNode qualifier to remove
295f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
296f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void removeQualifier(XMPNode qualNode)
297f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
298f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		PropertyOptions opts = getOptions();
299f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (qualNode.isLanguageNode())
300f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
301f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// if "xml:lang" is removed, remove hasLanguage-flag too
302f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			opts.setHasLanguage(false);
303f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
304f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else if (qualNode.isTypeNode())
305f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
306f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// if "rdf:type" is removed, remove hasType-flag too
307f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			opts.setHasType(false);
308f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
309f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
310f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		getQualifier().remove(qualNode);
311f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (qualifier.isEmpty())
312f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
313f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			opts.setHasQualifiers(false);
314f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			qualifier = null;
315f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
316f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
317f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
318f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
319f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
320f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
321f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Removes all qualifiers from the node and sets the options appropriate.
322f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
323f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void removeQualifiers()
324f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
325f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		PropertyOptions opts = getOptions();
326f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// clear qualifier related options
327f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		opts.setHasQualifiers(false);
328f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		opts.setHasLanguage(false);
329f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		opts.setHasType(false);
330f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		qualifier = null;
331f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
332f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
333f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
334f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
335f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param expr qualifier node name to look for
336f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns a qualifier <code>XMPNode</code> if node has been found,
337f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <code>null</code> otherwise.
338f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
339f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public XMPNode findQualifierByName(String expr)
340f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
341f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return find(qualifier, expr);
342f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
343f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
344f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
345f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
346f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns whether the node has children.
347f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
348f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public boolean hasChildren()
349f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
350f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return children != null  &&  children.size() > 0;
351f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
352f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
353f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
354f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
355f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns an iterator for the children.
356f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <em>Note:</em> take care to use it.remove(), as the flag are not adjusted in that case.
357f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
358f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public Iterator iterateChildren()
359f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
360f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (children != null)
361f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
362f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			return getChildren().iterator();
363f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
364f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else
365f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
366f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			return Collections.EMPTY_LIST.listIterator();
367f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
368f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
369f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
370f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
371f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
372f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns whether the node has qualifier attached.
373f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
374f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public boolean hasQualifier()
375f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
376f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return qualifier != null  &&  qualifier.size() > 0;
377f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
378f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
379f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
380f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
381f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns an iterator for the qualifier.
382f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <em>Note:</em> take care to use it.remove(), as the flag are not adjusted in that case.
383f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
384f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public Iterator iterateQualifier()
385f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
386f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (qualifier != null)
387f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
388f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			final Iterator it = getQualifier().iterator();
389f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
390f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			return new Iterator()
391f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
392f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				public boolean hasNext()
393f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				{
394f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					return it.hasNext();
395f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				}
396f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
397f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				public Object next()
398f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				{
399f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					return it.next();
400f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				}
401f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
402f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				public void remove()
403f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				{
404f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					throw new UnsupportedOperationException(
405f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling							"remove() is not allowed due to the internal contraints");
406f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				}
407f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
408f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			};
409f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
410f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else
411f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
412f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			return Collections.EMPTY_LIST.iterator();
413f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
414f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
415f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
416f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
417f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
418f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Performs a <b>deep clone</b> of the node and the complete subtree.
419f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
420f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @see java.lang.Object#clone()
421f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
422f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public Object clone()
423f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
424f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		PropertyOptions newOptions;
425f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		try
426f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
427f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			newOptions = new PropertyOptions(getOptions().getOptions());
428f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
429f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		catch (XMPException e)
430f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
431f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// cannot happen
432f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			newOptions = new PropertyOptions();
433f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
434f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
435f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		XMPNode newNode = new XMPNode(name, value, newOptions);
436f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		cloneSubtree(newNode);
437f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
438f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return newNode;
439f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
440f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
441f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
442f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
443f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Performs a <b>deep clone</b> of the complete subtree (children and
444f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * qualifier )into and add it to the destination node.
445f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
446f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param destination the node to add the cloned subtree
447f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
448f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void cloneSubtree(XMPNode destination)
449f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
450f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		try
451f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
452f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (Iterator it = iterateChildren(); it.hasNext();)
453f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
454f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				XMPNode child = (XMPNode) it.next();
455f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				destination.addChild((XMPNode) child.clone());
456f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
457f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
458f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (Iterator it = iterateQualifier(); it.hasNext();)
459f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
460f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				XMPNode qualifier = (XMPNode) it.next();
461f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				destination.addQualifier((XMPNode) qualifier.clone());
462f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
463f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
464f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		catch (XMPException e)
465f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
466f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// cannot happen (duplicate childs/quals do not exist in this node)
467f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			assert false;
468f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
469f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
470f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
471f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
472f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
473f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
474f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Renders this node and the tree unter this node in a human readable form.
475f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param recursive Flag is qualifier and child nodes shall be rendered too
476f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns a multiline string containing the dump.
477f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
478f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public String dumpNode(boolean recursive)
479f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
480f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		StringBuffer result = new StringBuffer(512);
481f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.dumpNode(result, recursive, 0, 0);
482f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return result.toString();
483f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
484f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
485f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
486f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
487f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @see Comparable#compareTo(Object)
488f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
489f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public int compareTo(Object xmpNode)
490f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
491f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (getOptions().isSchemaNode())
492f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
493f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			return this.value.compareTo(((XMPNode) xmpNode).getValue());
494f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
495f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else
496f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
497f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			return this.name.compareTo(((XMPNode) xmpNode).getName());
498f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
499f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
500f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
501f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
502f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
503f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the name.
504f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
505f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public String getName()
506f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
507f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return name;
508f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
509f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
510f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
511f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
512f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param name The name to set.
513f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
514f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setName(String name)
515f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
516f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.name = name;
517f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
518f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
519f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
520f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
521f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the value.
522f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
523f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public String getValue()
524f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
525f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return value;
526f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
527f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
528f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
529f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
530f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param value The value to set.
531f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
532f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setValue(String value)
533f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
534f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.value = value;
535f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
536f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
537f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
538f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
539f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the options.
540f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
541f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public PropertyOptions getOptions()
542f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
543f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (options == null)
544f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
545f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			options = new PropertyOptions();
546f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
547f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return options;
548f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
549f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
550f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
551f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
552f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Updates the options of the node.
553f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param options the options to set.
554f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
555f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setOptions(PropertyOptions options)
556f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
557f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.options = options;
558f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
559f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
560f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
561f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
562f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the implicit flag
563f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
564f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public boolean isImplicit()
565f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
566f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return implicit;
567f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
568f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
569f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
570f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
571f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param implicit Sets the implicit node flag
572f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
573f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setImplicit(boolean implicit)
574f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
575f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.implicit = implicit;
576f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
577f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
578f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
579f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
580f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns if the node contains aliases (applies only to schema nodes)
581f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
582f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public boolean getHasAliases()
583f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
584f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return hasAliases;
585f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
586f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
587f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
588f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
589f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param hasAliases sets the flag that the node contains aliases
590f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
591f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setHasAliases(boolean hasAliases)
592f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
593f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.hasAliases = hasAliases;
594f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
595f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
596f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
597f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
598f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns if the node contains aliases (applies only to schema nodes)
599f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
600f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public boolean isAlias()
601f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
602f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return alias;
603f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
604f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
605f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
606f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
607f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param alias sets the flag that the node is an alias
608f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
609f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setAlias(boolean alias)
610f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
611f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.alias = alias;
612f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
613f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
614f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
615f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
616f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return the hasValueChild
617f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
618f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public boolean getHasValueChild()
619f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
620f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return hasValueChild;
621f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
622f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
623f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
624f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
625f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param hasValueChild the hasValueChild to set
626f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
627f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void setHasValueChild(boolean hasValueChild)
628f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
629f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.hasValueChild = hasValueChild;
630f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
631f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
632f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
633f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
634f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
635f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Sorts the complete datamodel according to the following rules:
636f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <ul>
637f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * 		<li>Nodes at one level are sorted by name, that is prefix + local name
638f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * 		<li>Starting at the root node the children and qualifier are sorted recursively,
639f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * 			which the following exceptions.
640f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * 		<li>Sorting will not be used for arrays.
641f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * 		<li>Within qualifier "xml:lang" and/or "rdf:type" stay at the top in that order,
642f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * 			all others are sorted.
643f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * </ul>
644f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
645f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public void sort()
646f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
647f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// sort qualifier
648f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (hasQualifier())
649f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
650f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			XMPNode[] quals = (XMPNode[]) getQualifier()
651f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				.toArray(new XMPNode[getQualifierLength()]);
652f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			int sortFrom = 0;
653f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			while (
654f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					quals.length > sortFrom  &&
655f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					(XMPConst.XML_LANG.equals(quals[sortFrom].getName())  ||
656f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					 "rdf:type".equals(quals[sortFrom].getName()))
657f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				  )
658f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
659f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				quals[sortFrom].sort();
660f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				sortFrom++;
661f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
662f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
663f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			Arrays.sort(quals, sortFrom, quals.length);
664f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			ListIterator it = qualifier.listIterator();
665f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (int j = 0; j < quals.length; j++)
666f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
667f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				it.next();
668f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				it.set(quals[j]);
669f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				quals[j].sort();
670f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
671f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
672f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
673f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// sort children
674f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (hasChildren())
675f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
676f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			if (!getOptions().isArray())
677f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
678f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				Collections.sort(children);
679f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
680f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (Iterator it = iterateChildren(); it.hasNext();)
681f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
682f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				((XMPNode) it.next()).sort();
683f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
684f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
685f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
686f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
687f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
688f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
689f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
690f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	//------------------------------------------------------------------------------ private methods
691f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
692f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
693f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
694f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Dumps this node and its qualifier and children recursively.
695f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <em>Note:</em> It creats empty options on every node.
696f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
697f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param result the buffer to append the dump.
698f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param recursive Flag is qualifier and child nodes shall be rendered too
699f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param indent the current indent level.
700f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param index the index within the parent node (important for arrays)
701f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
702f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private void dumpNode(StringBuffer result, boolean recursive, int indent, int index)
703f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
704f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// write indent
705f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		for (int i = 0; i < indent; i++)
706f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
707f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append('\t');
708f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
709f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
710f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// render Node
711f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (parent != null)
712f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
713f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			if (getOptions().isQualifier())
714f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
715f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append('?');
716f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(name);
717f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
718f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			else if (getParent().getOptions().isArray())
719f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
720f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append('[');
721f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(index);
722f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(']');
723f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
724f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			else
725f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
726f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(name);
727f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
728f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
729f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		else
730f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
731f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			// applies only to the root node
732f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append("ROOT NODE");
733f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			if (name != null  &&  name.length() > 0)
734f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
735f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				// the "about" attribute
736f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(" (");
737f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(name);
738f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				result.append(')');
739f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
740f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
741f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
742f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (value != null  &&  value.length() > 0)
743f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
744f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append(" = \"");
745f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append(value);
746f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append('"');
747f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
748f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
749f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// render options if at least one is set
750f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (getOptions().containsOneOf(0xffffffff))
751f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
752f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append("\t(");
753f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append(getOptions().toString());
754f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append(" : ");
755f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append(getOptions().getOptionsString());
756f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			result.append(')');
757f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
758f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
759f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		result.append('\n');
760f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
761f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// render qualifier
762f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (recursive  &&  hasQualifier())
763f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
764f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			XMPNode[] quals = (XMPNode[]) getQualifier()
765f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				.toArray(new XMPNode[getQualifierLength()]);
766f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			int i = 0;
767f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			while (quals.length > i  &&
768f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					(XMPConst.XML_LANG.equals(quals[i].getName())  ||
769f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					 "rdf:type".equals(quals[i].getName()))
770f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				  )
771f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
772f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				i++;
773f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
774f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			Arrays.sort(quals, i, quals.length);
775f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (i = 0; i < quals.length; i++)
776f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
777f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				XMPNode qualifier = quals[i];
778f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				qualifier.dumpNode(result, recursive, indent + 2, i + 1);
779f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
780f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
781f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
782f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		// render children
783f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (recursive  &&  hasChildren())
784f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
785f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			XMPNode[] children = (XMPNode[]) getChildren()
786f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				.toArray(new XMPNode[getChildrenLength()]);
787f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			if (!getOptions().isArray())
788f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
789f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				Arrays.sort(children);
790f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
791f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (int i = 0; i < children.length; i++)
792f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
793f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				XMPNode child = children[i];
794f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				child.dumpNode(result, recursive, indent + 1, i + 1);
795f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
796f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
797f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
798f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
799f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
800f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
801f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns whether this node is a language qualifier.
802f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
803f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private boolean isLanguageNode()
804f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
805f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return XMPConst.XML_LANG.equals(name);
806f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
807f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
808f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
809f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
810f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns whether this node is a type qualifier.
811f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
812f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private boolean isTypeNode()
813f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
814f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return "rdf:type".equals(name);
815f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
816f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
817f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
818f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
819f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * <em>Note:</em> This method should always be called when accessing 'children' to be sure
820f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * that its initialized.
821f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns list of children that is lazy initialized.
822f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
823f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private List getChildren()
824f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
825f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (children == null)
826f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
827f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			children = new ArrayList(0);
828f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
829f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return children;
830f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
831f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
832f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
833f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
834f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns a read-only copy of child nodes list.
835f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
836f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	public List getUnmodifiableChildren()
837f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
838f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return Collections.unmodifiableList(new ArrayList(getChildren()));
839f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
840f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
841f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
842f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
843f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns list of qualifier that is lazy initialized.
844f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
845f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private List getQualifier()
846f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
847f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (qualifier == null)
848f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
849f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			qualifier = new ArrayList(0);
850f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
851f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return qualifier;
852f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
853f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
854f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
855f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
856f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Sets the parent node, this is solely done by <code>addChild(...)</code>
857f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * and <code>addQualifier()</code>.
858f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *
859f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param parent
860f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 *            Sets the parent node.
861f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
862f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	protected void setParent(XMPNode parent)
863f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
864f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		this.parent = parent;
865f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
866f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
867f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
868f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
869f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Internal find.
870f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param list the list to search in
871f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param expr the search expression
872f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @return Returns the found node or <code>nulls</code>.
873f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
874f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private XMPNode find(List list, String expr)
875f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
876f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
877f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (list != null)
878f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
879f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			for (Iterator it = list.iterator(); it.hasNext();)
880f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			{
881f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				XMPNode child = (XMPNode) it.next();
882f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				if (child.getName().equals(expr))
883f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				{
884f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					return child;
885f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling				}
886f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			}
887f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
888f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		return null;
889f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
890f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
891f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
892f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
893f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Checks that a node name is not existing on the same level, except for array items.
894f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param childName the node name to check
895f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @throws XMPException Thrown if a node with the same name is existing.
896f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
897f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private void assertChildNotExisting(String childName) throws XMPException
898f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
899f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (!XMPConst.ARRAY_ITEM_NAME.equals(childName)  &&
900f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			findChildByName(childName) != null)
901f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
902f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			throw new XMPException("Duplicate property or field node '" + childName + "'",
903f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling					XMPError.BADXMP);
904f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
905f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
906f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
907f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling
908f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	/**
909f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * Checks that a qualifier name is not existing on the same level.
910f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @param qualifierName the new qualifier name
911f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 * @throws XMPException Thrown if a node with the same name is existing.
912f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	 */
913f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	private void assertQualifierNotExisting(String qualifierName) throws XMPException
914f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	{
915f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		if (!XMPConst.ARRAY_ITEM_NAME.equals(qualifierName)  &&
916f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			findQualifierByName(qualifierName) != null)
917f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		{
918f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling			throw new XMPException("Duplicate '" + qualifierName + "' qualifier", XMPError.BADXMP);
919f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling		}
920f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling	}
921f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling}