KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xquery > reconstruction > ReconstructionVisitor


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  * Copyright (C) 2003 XQuark Group.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
19  * You can also get it at http://www.gnu.org/licenses/lgpl.html
20  *
21  * For more information on this software, see http://www.xquark.org.
22  */

23
24 package org.xquark.xquery.reconstruction;
25
26 import java.util.*;
27
28 import org.xml.sax.*;
29 import org.xml.sax.ext.LexicalHandler JavaDoc;
30 import org.xml.sax.helpers.AttributesImpl JavaDoc;
31 import org.xquark.schema.validation.PSVInfoSetProvider;
32 import org.xquark.schema.validation.ValidationContextProvider;
33 import org.xquark.util.NamespaceContextHandler;
34 import org.xquark.util.NamespaceContextStack;
35 import org.xquark.xml.xdbc.XMLDBCException;
36 import org.xquark.xquery.metadata.DynamicContext;
37 import org.xquark.xquery.parser.*;
38 import org.xquark.xquery.parser.primitivefunctions.fnfunctions.FunctionDATA;
39 import org.xquark.xquery.parser.primitivefunctions.fnfunctions.FunctionEXPANDED_QNAME;
40 import org.xquark.xquery.parser.primitivefunctions.xsfunctions.FunctionQNAME;
41 import org.xquark.xquery.typing.QType;
42 import org.xquark.xquery.xdbc.XDBCResultSetInterface;
43 import org.xquark.xquery.xdbc.XResultSetImpl;
44
45 public class ReconstructionVisitor extends DefaultParserVisitor {
46
47     private static final String JavaDoc RCSRevision = "$Revision: 1.4 $";
48     private static final String JavaDoc RCSName = "$Name: $";
49
50     private final String JavaDoc EMPTY_STRING = "";
51     private final String JavaDoc WHITE_SPACE = " ";
52     static final private String JavaDoc PREFIXROOT = "xqns";
53
54     //private ContentHandler contenthandler = null;
55
//private LexicalHandler lexicalhandler = null;
56
private ErrorHandler errorhandler = null;
57     private ReconstructionHandler reconstructionHandler = null;
58
59     private XResultSetImpl resultSet = null;
60     private XDBCResultSetInterface xdbcResultSet = null;
61     private EvaluationVisitor evalVisitor = null;
62
63     private AttributesImpl JavaDoc listAttributes = null;
64
65     private Object JavaDoc[] lastIdentifiers = null;
66     private Object JavaDoc[] currentIdentifiers = null;
67     private Object JavaDoc[] nextIdentifiers = null;
68     private boolean noNext = false;
69     private boolean noReconstructor = false;
70     private boolean hasidentifiers = false;
71
72     private boolean hasPrefixMapping = false;
73     private NamespaceContextStack declaredDeclarations = null;
74     private NamespaceContextStack reconstructionDeclarations = new NamespaceContextStack();
75
76     private ValidationContextProvider vcp = new ValidationContextProvider() {
77         public String JavaDoc getNamespaceURI(String JavaDoc prefix) {
78             return reconstructionDeclarations.getNamespaceURI(prefix);
79         }
80         public String JavaDoc getPrefix(String JavaDoc uri) {
81             return reconstructionDeclarations.getPrefix(uri);
82         }
83         public String JavaDoc getDocumentBase() {
84             return null;
85         }
86         public Map getNotationDeclarations() {
87             return null;
88         }
89     };
90
91     private int size = -1;
92     private ArrayList varList = null;
93     private int lastSkolemIDsSize = -1;
94     private ArrayList lastDependIDs = null;
95
96     private boolean evalNeeded = false;
97     private String JavaDoc evalResultNamespace = null;
98     private String JavaDoc evalResultValue = null;
99
100     private boolean root = true;
101     private boolean noResultSet = false;
102     private boolean noReInit = false;
103     private ArrayList skolemIDs = null;
104
105     private DynamicContext dc = null;
106     private PSVInfoSetProvider psvisp = null;
107
108     private class ReconstructionHandler extends NamespaceContextHandler {
109         private final String JavaDoc WHITE_SPACE = " ";
110
111         private boolean prevIsOnlyChars = false;
112         private boolean isOnlyChars = false;
113
114         public boolean IsOnlyChars() {
115             return isOnlyChars;
116         }
117
118         public void reset(boolean prev) {
119             prevIsOnlyChars = prev;
120         }
121
122         public void characters(char[] values, int start, int length) throws SAXException {
123             if (prevIsOnlyChars) {
124                 super.characters(WHITE_SPACE.toCharArray(), 0, 1);
125             }
126             if (!isOnlyChars)
127                 isOnlyChars = true;
128             super.characters(values, start, length);
129         }
130
131         public void startElement(String JavaDoc uri, String JavaDoc localname, String JavaDoc qname, Attributes attributes) throws SAXException {
132             contextStack.pushContext();
133             checkPrefix(uri);
134             for (int i = 0; i < attributes.getLength(); i++) {
135                 checkPrefix(attributes.getURI(i));
136             }
137             super.startElement(uri, localname, qname, attributes);
138             if (isOnlyChars)
139                 isOnlyChars = false;
140             if (prevIsOnlyChars)
141                 prevIsOnlyChars = false;
142         }
143
144         private void checkPrefix(String JavaDoc uri) throws SAXException {
145             if (uri == null || uri.length() == 0)
146                 return;
147             if (getPrefix(uri) == null) {
148                 String JavaDoc prefix = (declaredDeclarations == null) ? null : declaredDeclarations.getPrefix(uri);
149                 if (prefix == null) {
150                     for (int i = 1;; i++) {
151                         String JavaDoc genPrefix = PREFIXROOT + i;
152                         if (getNamespaceURI(genPrefix) == null) {
153                             prefix = genPrefix;
154                             break;
155                         }
156                     }
157                 }
158                 this.startPrefixMapping(prefix, uri);
159             }
160         }
161
162         public void processingInstruction(String JavaDoc str, String JavaDoc str1) throws SAXException {
163             super.processingInstruction(str, str1);
164             if (isOnlyChars)
165                 isOnlyChars = false;
166             if (prevIsOnlyChars)
167                 prevIsOnlyChars = false;
168         }
169
170         public void endElement(String JavaDoc uri, String JavaDoc localname, String JavaDoc qname) throws SAXException {
171             super.endElement(uri, localname, qname);
172             List list = contextStack.getDeclaredPrefixes();
173             for (int i = 0; i < list.size(); i++)
174                 this.endPrefixMapping((String JavaDoc) list.get(i));
175             contextStack.popContext();
176             if (isOnlyChars)
177                 isOnlyChars = false;
178             if (prevIsOnlyChars)
179                 prevIsOnlyChars = false;
180         }
181     }
182
183     public ReconstructionVisitor(XResultSetImpl resultSet, ArrayList varList) {
184         this.reconstructionHandler = new ReconstructionHandler();
185         this.resultSet = resultSet;
186         this.xdbcResultSet = resultSet.getXDBCResultSet();
187         if (xdbcResultSet != null) {
188             xdbcResultSet.setContentHandler(reconstructionHandler);
189             xdbcResultSet.setLexicalHandler(reconstructionHandler);
190         }
191         psvisp = resultSet.getPSVInfoSetProvider();
192         this.varList = varList;
193         size = varList.size();
194         currentIdentifiers = new Object JavaDoc[size];
195         nextIdentifiers = new Object JavaDoc[size];
196         lastIdentifiers = new Object JavaDoc[size];
197         listAttributes = new AttributesImpl JavaDoc();
198         evalVisitor = new EvaluationVisitor(xdbcResultSet, vcp);
199     }
200
201     public void reInit() {
202         if (!noReInit)
203             noNext = false;
204         else
205             noReInit = false;
206         root = true;
207         hasPrefixMapping = false;
208         hasidentifiers = false;
209     }
210
211     private void setIdentifiers(boolean force) throws XQueryException {
212         if (!force && hasidentifiers)
213             return;
214         try {
215             if (xdbcResultSet.hasNext())
216                 xdbcResultSet.getNextIdentifiers(nextIdentifiers);
217             if (!this.noResultSet)
218                 xdbcResultSet.getIdentifiers(currentIdentifiers);
219             hasidentifiers = true;
220         } catch (XMLDBCException xmldbce) {
221             throw new XQueryException(xmldbce.getMessage());
222         }
223     }
224
225     public void setContentHandler(ContentHandler handler) {
226         reconstructionHandler.setContentHandler(handler);
227         if (xdbcResultSet != null)
228             xdbcResultSet.setContentHandler(reconstructionHandler);
229     }
230
231     /**
232      * @see XDBCResultSetInterface#setLexicalHandler
233      */

234     public void setLexicalHandler(LexicalHandler JavaDoc handler) {
235         reconstructionHandler.setLexicalHandler(handler);
236         if (xdbcResultSet != null)
237             xdbcResultSet.setLexicalHandler(reconstructionHandler);
238     }
239
240     /**
241      * @see XDBCResultSetInterface#setErrorHandler
242      */

243     public void setErrorHandler(ErrorHandler handler) {
244         errorhandler = handler;
245     }
246
247     public XResultSetImpl getResultSet() {
248         return resultSet;
249     }
250     /*
251     public ContentHandler getContentHandler() {
252         return reconstructionHandler.getContentHandler();
253     }
254     public LexicalHandler getLexicalHandler() {
255         return reconstructionHandler.getLexicalHandler();
256     }
257     public ErrorHandler getErrorHandler() {
258         return errorhandler;
259     }
260     */

261     public boolean getNoReconstructor() {
262         return noReconstructor;
263     }
264     public boolean getNoNext() {
265         return noNext;
266     }
267     public boolean getNoResultSet() {
268         return noResultSet;
269     }
270     public void setNoResultSet(boolean noResultSet) {
271         this.noResultSet = noResultSet;
272     }
273     public void setNamespaceDecl(NamespaceContextStack declarations) {
274         hasPrefixMapping = true;
275         this.declaredDeclarations = declarations;
276     }
277     public void setDynamicContext(DynamicContext dc) {
278         this.dc = dc;
279         evalVisitor.setDynamicContext(dc);
280     }
281     // visitor ...
282

283     // public void visit(AggregateFunctionCall arg) throws XQueryException
284

285     private void outputAttributeValuePair(AttributeValuePair arg) throws XQueryException {
286         if (arg.isXmlns())
287             return;
288         String JavaDoc nameSpaceAtt = EMPTY_STRING;
289         String JavaDoc localNameAtt = EMPTY_STRING;
290         String JavaDoc value = EMPTY_STRING;
291         XQueryExpression attrName = arg.getAttributeName();
292         evalVisitor.setReturnType(EvaluationVisitor.VALUE_TYPE);
293         attrName.accept(evalVisitor);
294         Comparable JavaDoc comp = evalVisitor.getResValue();
295         if (comp != null) {
296             // this is not nice but for now it works fine
297
String JavaDoc compStr = comp.toString();
298             if (compStr.startsWith("{")) {
299                 int ind = compStr.lastIndexOf('}');
300                 if (ind == -1)
301                     localNameAtt = compStr;
302                 else {
303                     nameSpaceAtt = compStr.substring(1, ind);
304                     localNameAtt = compStr.substring(ind + 1);
305                 }
306             } else {
307                 int ind = compStr.lastIndexOf(':');
308                 if (ind == -1)
309                     localNameAtt = compStr;
310                 else {
311                     String JavaDoc prefix = compStr.substring(0, ind);
312                     nameSpaceAtt = reconstructionDeclarations.getNamespaceURI(prefix);
313                     if (nameSpaceAtt == null) {
314                         if (declaredDeclarations != null)
315                             nameSpaceAtt = declaredDeclarations.getNamespaceURI(prefix);
316                         if (nameSpaceAtt != null)
317                             reconstructionDeclarations.declarePrefix(prefix, nameSpaceAtt);
318                     }
319                     localNameAtt = compStr.substring(ind + 1);
320                 }
321             }
322         }
323         XQueryExpression attrValue = arg.getAttributeValue();
324         evalVisitor.setReturnType(EvaluationVisitor.VALUE_TYPE);
325         attrValue.accept(evalVisitor);
326         comp = evalVisitor.getResValue();
327         if (comp != null)
328             value = comp.toString();
329         // test if attribute already exists
330
if (listAttributes.getValue(nameSpaceAtt, localNameAtt) != null)
331             throw new ReconstructionException("An element cannot have several attributes with the same name.");
332         // add attribute
333
listAttributes.addAttribute((nameSpaceAtt == null ? "" : nameSpaceAtt), localNameAtt, "", "STRING", value);
334         // reset key variables
335
skolemIDs = arg.getSkolemIDs();
336         if (skolemIDs != null)
337             lastSkolemIDsSize = skolemIDs.size();
338     }
339
340     public void visit(AttributeValuePair arg) throws XQueryException {
341         if (arg.isXmlns())
342             return;
343         boolean isSkolemID = false;
344         boolean isDependID = false;
345         boolean putPrefixMapping = false;
346         noReconstructor = true;
347         skolemIDs = arg.getSkolemIDs();
348         if (skolemIDs != null)
349             lastSkolemIDsSize = skolemIDs.size();
350         if ((skolemIDs != null && !skolemIDs.isEmpty()) || arg.getRoot())
351             isSkolemID = true;
352         ArrayList dependIDs = arg.getDependIDs();
353         if (dependIDs != null && !dependIDs.isEmpty())
354             isDependID = true;
355         boolean loop = arg.getLoop();
356
357         // CASE : this element has no skolem ids
358
if (!isSkolemID) {
359             // CASE : the element is written until there are no more results available
360
if (loop) {
361                 // no not continue if dependIDs changed
362
if (this.noResultSet && dependIDs != lastDependIDs)
363                     return;
364                 while (true) {
365                     // WRITE SONS
366
boolean previousRoot = root;
367                     root = false;
368                     outputAttributeValuePair(arg);
369                     root = previousRoot;
370                     noReconstructor = true;
371                     if (hasNext())
372                         nextAsSAX();
373                     else
374                         break;
375                 }
376             }
377             // CASE : no loop and element has depend ids
378
else if (isDependID) {
379                 noNext = false;
380                 boolean changeDependIDs = true;
381                 /// !!! DANGER !!! THIS is stupid code!!! ( )
382
try {
383                     this.setIdentifiers(false);
384                 } catch (XQueryException e) {
385                     changeDependIDs = false;
386                 }
387                 while (!isEmpty(dependIDs) && changeDependIDs) {
388                     // WRITE SONS
389
boolean previousRoot = root;
390                     root = false;
391                     outputAttributeValuePair(arg);
392                     root = previousRoot;
393                     if (!hasNext())
394                         break;
395                     changeDependIDs = changeDependIDs(currentIdentifiers, nextIdentifiers, dependIDs);
396                     if (!changeDependIDs) {
397                         noNext = false;
398                         break;
399                     } else if (!isEmpty(dependIDs))
400                         noNext = false;
401                     if (!noNext) {
402                         noReconstructor = true;
403                         if (!hasNext())
404                             break;
405                         identifierCopy(currentIdentifiers, lastIdentifiers);
406                         nextAsSAX();
407                         this.setIdentifiers(true);
408                     }
409                     if (changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs))
410                         noNext = true;
411                 }
412             } else {
413                 // WRITE SONS
414
boolean previousRoot = root;
415                 root = false;
416                 outputAttributeValuePair(arg);
417                 root = previousRoot;
418             }
419         }
420         // there is at least a skolemID
421
else {
422
423             // set the current identifier and the next
424
if (isSkolemID && !arg.getRoot()) {
425                 this.setIdentifiers(false);
426             }
427             // there is no dependID
428
if (dependIDs == null && !arg.getRoot()) {
429                 // CODE NOT USED !!! AS FAR AS I CAN TELL
430
if (loop) {
431                     while (true) {
432                         // WRITE SONS
433
boolean previousRoot = root;
434                         root = false;
435                         outputAttributeValuePair(arg);
436                         root = previousRoot;
437                         noReconstructor = true;
438                         noNext = false;
439                         if (hasNext())
440                             nextAsSAX();
441                         else
442                             break;
443                     }
444                 } else {
445                     // WRITE SONS
446
boolean previousRoot = root;
447                     root = false;
448                     outputAttributeValuePair(arg);
449                     root = previousRoot;
450                 }
451             } else // dependIDs != null or arg element is root
452
{
453                 noNext = false;
454                 if (!arg.getRoot() && lastSkolemIDsSize < skolemIDs.size()) {
455                     boolean changeDependIDs = true;
456                     boolean changeSkolemIDs = changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs, lastSkolemIDsSize);
457                     // stop if the skolemIDs changed, and that dependIDs does not have an incidence
458
if (dependIDs != null && dependIDs.isEmpty() && changeSkolemIDs) {
459                         return;
460                     }
461
462                     int firstDependIDPosition = 0;
463                     if (dependIDs != null && !dependIDs.isEmpty()) {
464                         firstDependIDPosition = getPosition((Variable) dependIDs.get(0)) + 1;
465                     }
466                     int skipEntries = -1;
467                     if (firstDependIDPosition > skolemIDs.size()) {
468                         skipEntries = lastSkolemIDsSize;
469                         while (!changeSkolemIDs && isEmpty(dependIDs)) {
470                             if (!hasNext())
471                                 break;
472                             identifierCopy(currentIdentifiers, lastIdentifiers);
473                             nextAsSAX();
474                             this.setIdentifiers(true);
475                             changeSkolemIDs = changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs, lastSkolemIDsSize);
476                             changeDependIDs = changeDependIDs(currentIdentifiers, nextIdentifiers, skolemIDs, dependIDs, lastSkolemIDsSize);
477                         }
478                     }
479                     while (!isEmpty(dependIDs) && changeDependIDs) {
480                         // WRITE SONS
481
boolean previousRoot = root;
482                         root = false;
483                         outputAttributeValuePair(arg);
484                         root = previousRoot;
485                         if (!hasNext())
486                             break;
487                         if (skipEntries == -1) {
488                             changeDependIDs = changeDependIDs(currentIdentifiers, nextIdentifiers, skolemIDs, dependIDs, firstDependIDPosition - 1);
489                             if (!changeDependIDs) {
490                                 noNext = false;
491                                 break;
492                             } else if (!isEmpty(dependIDs))
493                                 noNext = false;
494                         }
495                         // ----------------------------
496
// ADDED
497
//-----------------------------
498
else {
499                             changeSkolemIDs = changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs, skipEntries);
500                             changeDependIDs = changeDependIDs(currentIdentifiers, nextIdentifiers, skolemIDs, dependIDs, skipEntries);
501                             if (!changeSkolemIDs) {
502                                 noNext = false;
503                                 boolean noDependIDs = true;
504                                 boolean makeBreak = false;
505                                 noReInit = false;
506                                 while (!changeSkolemIDs && noDependIDs) {
507                                     noReconstructor = true;
508                                     if (!hasNext()) {
509                                         makeBreak = true;
510                                         break;
511                                     }
512                                     identifierCopy(currentIdentifiers, lastIdentifiers);
513                                     nextAsSAX();
514                                     this.setIdentifiers(true);
515                                     changeSkolemIDs = changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs, skipEntries);
516                                     noDependIDs = isEmpty(dependIDs);
517                                 }
518                                 if (makeBreak)
519                                     break;
520                                 noNext = true;
521                                 if (!noDependIDs)
522                                     noReInit = true;
523                                 changeDependIDs = true;
524                             } else if (!isEmpty(dependIDs))
525                                 noNext = false;
526                         }
527                         // ----------------------------
528
// END ADDED
529
//-----------------------------
530
if (!noNext && !changeSkolemIDs) {
531                             noReconstructor = true;
532                             if (!hasNext())
533                                 break;
534                             identifierCopy(currentIdentifiers, lastIdentifiers);
535                             nextAsSAX();
536                             this.setIdentifiers(true);
537                         }
538                         if (skipEntries == -1) {
539                             if (changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs))
540                                 noNext = true;
541                         } else {
542                             if (changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs, skipEntries))
543                                 noNext = false; // CHANGE 03/07/2002 was initially true
544
}
545                     }
546                 } else {
547                     boolean changeSkolemIDs = false;
548                     while (arg.getRoot() || (!isEmpty(dependIDs) && !changeSkolemIDs)) {
549                         // set last dependIDs
550
lastDependIDs = dependIDs;
551                         // WRITE SONS
552
boolean previousRoot = root;
553                         root = false;
554                         outputAttributeValuePair(arg);
555                         root = previousRoot;
556                         if (!hasNext())
557                             break;
558                         if (!arg.getRoot())
559                             changeSkolemIDs = changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs);
560                         if (!noNext && !arg.getRoot() && !isEmpty(dependIDs) && !changeSkolemIDs) {
561                             noReconstructor = true;
562                             if (!hasNext())
563                                 break;
564                             identifierCopy(currentIdentifiers, lastIdentifiers);
565                             nextAsSAX();
566                             this.setIdentifiers(true);
567                         }
568                         if (changeSkolemIDs)
569                             noNext = true;
570                         if (arg.getRoot())
571                             break;
572                     }
573                     // while (!changeSkolemIDs);
574
}
575                 // noNext = true;
576
}
577         }
578         noReconstructor = false;
579     }
580
581     // public void visit(BinOpANDExpression arg) throws XQueryException;
582
// public void visit(BinOpORExpression arg) throws XQueryException;
583
// public void visit(CastTreatExpression arg) throws XQueryException;
584

585     public void visit(CData arg) throws XQueryException {
586         try {
587             reconstructionHandler.startCDATA();
588             characters(arg.getCData().toCharArray(), 0, arg.getCData().length());
589             reconstructionHandler.endCDATA();
590         } catch (SAXException e) {
591             throw new XQueryException(e.getMessage());
592         }
593     }
594
595     // public void visit(ContextDeclaration arg) throws XQueryException;
596

597     private void outputComputedText(ComputedText arg) throws XQueryException {
598         evalNeeded = true;
599         arg.getExpression().accept(this);
600         evalNeeded = false;
601         if (evalResultValue != null) {
602             characters(evalResultValue.toCharArray(), 0, evalResultValue.length());
603             reconstructionHandler.reset(true);
604             evalResultValue = null;
605         }
606         // reset key variables
607
skolemIDs = arg.getSkolemIDs();
608         if (skolemIDs != null)
609             lastSkolemIDsSize = skolemIDs.size();
610     }
611
612     public void visit(ComputedText arg) throws XQueryException {
613
614         boolean isSkolemID = false;
615         boolean isDependID = false;
616         boolean putPrefixMapping = false;
617         noReconstructor = true;
618         skolemIDs = arg.getSkolemIDs();
619         if ((skolemIDs != null && !skolemIDs.isEmpty()) || arg.getRoot())
620             isSkolemID = true;
621         ArrayList dependIDs = arg.getDependIDs();
622         if (dependIDs != null && !dependIDs.isEmpty())
623             isDependID = true;
624         boolean loop = arg.getLoop();
625
626         // CASE : this element has no skolem ids
627
if (!isSkolemID) {
628             // CASE : the element is written until there are no more results available
629
if (loop) {
630                 // no not continue if dependIDs changed
631
if (this.noResultSet && dependIDs != lastDependIDs)
632                     return;
633                 while (true) {
634                     // WRITE SONS
635
boolean previousRoot = root;
636                     root = false;
637                     outputComputedText(arg);
638                     root = previousRoot;
639                     noReconstructor = true;
640                     if (hasNext())
641                         nextAsSAX();
642                     else
643                         break;
644                 }
645             }
646             // CASE : no loop and element has depend ids
647
else if (isDependID) {
648                 noNext = false;
649                 boolean changeDependIDs = true;
650                 /// !!! DANGER !!! THIS is stupid code!!! ( )
651
try {
652                     this.setIdentifiers(false);
653                 } catch (XQueryException e) {
654                     changeDependIDs = false;
655                 }
656                 while (!isEmpty(dependIDs) && changeDependIDs) {
657                     // WRITE SONS
658
boolean previousRoot = root;
659                     root = false;
660                     outputComputedText(arg);
661                     root = previousRoot;
662                     if (!hasNext())
663                         break;
664                     changeDependIDs = changeDependIDs(currentIdentifiers, nextIdentifiers, dependIDs);
665                     if (!changeDependIDs) {
666                         noNext = false;
667                         break;
668                     } else if (!isEmpty(dependIDs))
669                         noNext = false;
670                     if (!noNext) {
671                         noReconstructor = true;
672                         if (!hasNext())
673                             break;
674                         identifierCopy(currentIdentifiers, lastIdentifiers);
675                         nextAsSAX();
676                         this.setIdentifiers(true);
677                     }
678                     if (changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs))
679                         noNext = true;
680                 }
681             } else {
682                 // WRITE SONS
683
boolean previousRoot = root;
684                 root = false;
685                 outputComputedText(arg);
686