001: // Copyright (c) 2003 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.kawa.xml;
005:
006: import gnu.mapping.Values;
007: import gnu.lists.*;
008: import gnu.xml.*;
009:
010: /* #ifdef use:org.w3c.dom.Node */
011: // import org.w3c.dom.*;
012: /* #endif */
013:
014: /** Manages a sequence of node references. */
015:
016: public class Nodes extends Values
017: /* #ifdef use:org.w3c.dom.Node */
018: // implements org.w3c.dom.NodeList
019: /* #endif */
020: {
021: /** Number of data elements for a POSITION_PAIR_FOLLOWS node reference. */
022: static final int POS_SIZE = 5;
023:
024: int count;
025:
026: int nesting = 0;
027: boolean inAttribute;
028: NodeTree curNode;
029: XMLFilter curFragment;
030:
031: public void writePosition(AbstractSequence seq, int ipos) {
032: count++;
033: super .writePosition(seq, ipos);
034: }
035:
036: public int find(Object seq) {
037: // See if can re-use the object index of the position before the gap.
038: if (gapStart > 0) {
039: int oindex = getIntN(gapStart - POS_SIZE + 1);
040: if (objects[oindex] == seq)
041: return oindex;
042: }
043: // See if can re-use the object index of the position after the gap.
044: if (gapEnd < data.length) {
045: int oindex = getIntN(gapEnd + 1);
046: if (objects[oindex] == seq)
047: return oindex;
048: }
049: return super .find(seq);
050: }
051:
052: public void writeObject(Object v) {
053: if (curFragment != null) {
054: if (nesting == 0
055: && (v instanceof SeqPosition || v instanceof TreeList))
056: finishFragment();
057: else {
058: curFragment.writeObject(v);
059: return;
060: }
061: }
062: if (v instanceof SeqPosition) {
063: SeqPosition seq = (SeqPosition) v;
064: writePosition(seq.sequence, seq.ipos);
065: return;
066: }
067: if (v instanceof TreeList) {
068: TreeList tlist = (TreeList) v;
069: writePosition(tlist, 0);
070: return;
071: }
072: handleNonNode();
073: curFragment.writeObject(v);
074: return;
075: }
076:
077: void maybeStartTextNode() {
078: if (curFragment == null) {
079: throw new IllegalArgumentException(
080: "non-node where node required");
081: }
082: }
083:
084: void handleNonNode() {
085: if (curFragment == null) {
086: throw new ClassCastException(
087: "atomic value where node is required");
088: }
089: }
090:
091: public void writeFloat(float v) {
092: handleNonNode();
093: curFragment.writeFloat(v);
094: }
095:
096: public void writeDouble(double v) {
097: handleNonNode();
098: curFragment.writeDouble(v);
099: }
100:
101: public void writeLong(long v) {
102: handleNonNode();
103: curFragment.writeLong(v);
104: }
105:
106: public void writeInt(int v) {
107: handleNonNode();
108: curFragment.writeInt(v);
109: }
110:
111: public void writeBoolean(boolean v) {
112: handleNonNode();
113: curFragment.writeBoolean(v);
114: }
115:
116: public void write(int v) {
117: maybeStartTextNode();
118: curFragment.write(v);
119: }
120:
121: /* #ifdef use:java.lang.CharSequence */
122: public Consumer append(CharSequence csq, int start, int end) {
123: maybeStartTextNode();
124: curFragment.write(csq, start, end);
125: return this ;
126: }
127:
128: /* #endif */
129:
130: public void write(char[] buf, int off, int len) {
131: maybeStartTextNode();
132: curFragment.write(buf, off, len);
133: }
134:
135: /* #ifdef use:java.lang.CharSequence */
136: public void write(CharSequence str, int start, int length)
137: /* #else */
138: // public void write(String str, int start, int length)
139: /* #endif */
140: {
141: maybeStartTextNode();
142: curFragment.write(str, start, length);
143: }
144:
145: public void write(String str) {
146: maybeStartTextNode();
147: curFragment.write(str);
148: }
149:
150: private void maybeStartNonTextNode() {
151: if (curFragment != null && nesting == 0)
152: finishFragment();
153: if (curFragment == null)
154: startFragment();
155: nesting++;
156: }
157:
158: private void maybeEndNonTextNode() {
159: if (--nesting == 0)
160: finishFragment();
161: }
162:
163: public void startElement(Object type) {
164: maybeStartNonTextNode();
165: curFragment.startElement(type);
166: }
167:
168: public void endElement() {
169: curFragment.endElement();
170: maybeEndNonTextNode();
171: }
172:
173: public void startAttribute(Object attrType) {
174: maybeStartNonTextNode();
175: curFragment.startAttribute(attrType);
176: inAttribute = true;
177: }
178:
179: public void endAttribute() {
180: if (!inAttribute)
181: return;
182: inAttribute = false;
183: curFragment.endAttribute();
184: maybeEndNonTextNode();
185: }
186:
187: public void writeComment(char[] chars, int offset, int length) {
188: maybeStartNonTextNode();
189: curFragment.writeComment(chars, offset, length);
190: maybeEndNonTextNode();
191: }
192:
193: public void writeCDATA(char[] chars, int offset, int length) {
194: maybeStartNonTextNode();
195: curFragment.writeCDATA(chars, offset, length);
196: }
197:
198: public void writeProcessingInstruction(String target,
199: char[] content, int offset, int length) {
200: maybeStartNonTextNode();
201: curFragment.writeProcessingInstruction(target, content, offset,
202: length);
203: maybeEndNonTextNode();
204: }
205:
206: public void startDocument() {
207: maybeStartNonTextNode();
208: curFragment.startDocument();
209: }
210:
211: public void endDocument() {
212: curFragment.endDocument();
213: maybeEndNonTextNode();
214: }
215:
216: public void beginEntity(Object base) {
217: maybeStartNonTextNode();
218: curFragment.beginEntity(base);
219: }
220:
221: public void endEntity() {
222: curFragment.endEntity();
223: maybeEndNonTextNode();
224: }
225:
226: void startFragment() {
227: curNode = new NodeTree();
228: curFragment = new XMLFilter(curNode);
229: writePosition(curNode, 0);
230: }
231:
232: void finishFragment() {
233: curNode = null;
234: curFragment = null;
235: }
236:
237: public int size() {
238: return count;
239: }
240:
241: public int getLength() {
242: return count;
243: }
244:
245: public Object get(int index) {
246: int i = POS_SIZE * index;
247: if (i >= gapStart)
248: i += gapEnd - gapStart;
249: if (i < 0 || i >= data.length)
250: throw new IndexOutOfBoundsException();
251: // Inline of: return getPosNext(i << 1)
252: if (data[i] != POSITION_PAIR_FOLLOWS)
253: throw new RuntimeException(
254: "internal error - unexpected data");
255: return KNode.make((NodeTree) objects[getIntN(i + 1)],
256: getIntN(i + 3));
257: }
258:
259: /* #ifdef use:org.w3c.dom.Node */
260: // public Node item(int index)
261: // {
262: // if (index >= count)
263: // return null;
264: // else
265: // return (Node) get(index);
266: // }
267: /* #endif */
268:
269: public Object getPosNext(int ipos) {
270: int index = posToDataIndex(ipos);
271: if (index == data.length)
272: return Sequence.eofValue;
273: if (data[index] != POSITION_PAIR_FOLLOWS)
274: throw new RuntimeException(
275: "internal error - unexpected data");
276: return KNode.make((NodeTree) objects[getIntN(index + 1)],
277: getIntN(index + 3));
278: }
279:
280: /** Optimization of ((SeqPosition) get(index)).sequence.
281: * However returns null instead of throwing IndexOutOfBoundsException
282: * if index >= count. */
283: public AbstractSequence getSeq(int index) {
284: int i = POS_SIZE * index;
285: if (i >= gapStart)
286: i += gapEnd - gapStart;
287: if (i < 0 || i >= data.length)
288: return null;
289: // Inline of: return getPosNext(i << 1)
290: if (data[i] != POSITION_PAIR_FOLLOWS)
291: throw new RuntimeException(
292: "internal error - unexpected data");
293: return (AbstractSequence) objects[getIntN(i + 1)];
294: }
295:
296: /** Optimization of ((SeqPosition) get(index)). ipos. */
297: public int getPos(int index) {
298: int i = POS_SIZE * index;
299: if (i >= gapStart)
300: i += gapEnd - gapStart;
301: // Inline of: return getPosNext(i << 1)
302: if (data[i] != POSITION_PAIR_FOLLOWS)
303: throw new RuntimeException(
304: "internal error - unexpected data");
305: return getIntN(i + 3);
306: }
307:
308: public static KNode root(NodeTree seq, int ipos) {
309: int root;
310: if (seq.gapStart > TreeList.BEGIN_ENTITY_SIZE
311: && seq.data[0] == TreeList.BEGIN_ENTITY)
312: root = TreeList.BEGIN_ENTITY_SIZE << 1;
313: else
314: root = 0;
315: return KNode.make(seq, root);
316: /*
317: int end = seq.endPos();
318: for (;;)
319: {
320: int parent = seq.parentPos(ipos);
321: if (parent == end)
322: return KNode.make(seq, ipos);
323: ipos = parent;
324: }
325: */
326: }
327: }
|