| 1 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 ; 30 import org.xml.sax.helpers.AttributesImpl ; 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 RCSRevision = "$Revision: 1.4 $"; 48 private static final String RCSName = "$Name: $"; 49 50 private final String EMPTY_STRING = ""; 51 private final String WHITE_SPACE = " "; 52 static final private String PREFIXROOT = "xqns"; 53 54 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 listAttributes = null; 64 65 private Object [] lastIdentifiers = null; 66 private Object [] currentIdentifiers = null; 67 private Object [] 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 getNamespaceURI(String prefix) { 78 return reconstructionDeclarations.getNamespaceURI(prefix); 79 } 80 public String getPrefix(String uri) { 81 return reconstructionDeclarations.getPrefix(uri); 82 } 83 public String 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 evalResultNamespace = null; 98 private String 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 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 uri, String localname, String 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 uri) throws SAXException { 145 if (uri == null || uri.length() == 0) 146 return; 147 if (getPrefix(uri) == null) { 148 String prefix = (declaredDeclarations == null) ? null : declaredDeclarations.getPrefix(uri); 149 if (prefix == null) { 150 for (int i = 1;; i++) { 151 String 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 str, String 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 uri, String localname, String 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 ) 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 [size]; 195 nextIdentifiers = new Object [size]; 196 lastIdentifiers = new Object [size]; 197 listAttributes = new AttributesImpl (); 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 234 public void setLexicalHandler(LexicalHandler handler) { 235 reconstructionHandler.setLexicalHandler(handler); 236 if (xdbcResultSet != null) 237 xdbcResultSet.setLexicalHandler(reconstructionHandler); 238 } 239 240 243 public void setErrorHandler(ErrorHandler handler) { 244 errorhandler = handler; 245 } 246 247 public XResultSetImpl getResultSet() { 248 return resultSet; 249 } 250 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 283 285 private void outputAttributeValuePair(AttributeValuePair arg) throws XQueryException { 286 if (arg.isXmlns()) 287 return; 288 String nameSpaceAtt = EMPTY_STRING; 289 String localNameAtt = EMPTY_STRING; 290 String value = EMPTY_STRING; 291 XQueryExpression attrName = arg.getAttributeName(); 292 evalVisitor.setReturnType(EvaluationVisitor.VALUE_TYPE); 293 attrName.accept(evalVisitor); 294 Comparable comp = evalVisitor.getResValue(); 295 if (comp != null) { 296 String 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 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 if (listAttributes.getValue(nameSpaceAtt, localNameAtt) != null) 331 throw new ReconstructionException("An element cannot have several attributes with the same name."); 332 listAttributes.addAttribute((nameSpaceAtt == null ? "" : nameSpaceAtt), localNameAtt, "", "STRING", value); 334 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 if (!isSkolemID) { 359 if (loop) { 361 if (this.noResultSet && dependIDs != lastDependIDs) 363 return; 364 while (true) { 365 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 else if (isDependID) { 379 noNext = false; 380 boolean changeDependIDs = true; 381 try { 383 this.setIdentifiers(false); 384 } catch (XQueryException e) { 385 changeDependIDs = false; 386 } 387 while (!isEmpty(dependIDs) && changeDependIDs) { 388 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 boolean previousRoot = root; 415 root = false; 416 outputAttributeValuePair(arg); 417 root = previousRoot; 418 } 419 } 420 else { 422 423 if (isSkolemID && !arg.getRoot()) { 425 this.setIdentifiers(false); 426 } 427 if (dependIDs == null && !arg.getRoot()) { 429 if (loop) { 431 while (true) { 432 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 boolean previousRoot = root; 447 root = false; 448 outputAttributeValuePair(arg); 449 root = previousRoot; 450 } 451 } else { 453 noNext = false; 454 if (!arg.getRoot() && lastSkolemIDsSize < skolemIDs.size()) { 455 boolean changeDependIDs = true; 456 boolean changeSkolemIDs = changeSkolemIDs(currentIdentifiers, nextIdentifiers, skolemIDs, lastSkolemIDsSize); 457 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 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 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 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; } 545 } 546 } else { 547 boolean changeSkolemIDs = false; 548 while (arg.getRoot() || (!isEmpty(dependIDs) && !changeSkolemIDs)) { 549 lastDependIDs = dependIDs; 551 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 } 575 } 577 } 578 noReconstructor = false; 579 } 580 581 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 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 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 if (!isSkolemID) { 628 if (loop) { 630 if (this.noResultSet && dependIDs != lastDependIDs) 632 return; 633 while (true) { 634 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 else if (isDependID) { 648 noNext = false; 649 boolean changeDependIDs = true; 650 try { 652 this.setIdentifiers(false); 653 } catch (XQueryException e) { 654 changeDependIDs = false; 655 } 656 while (!isEmpty(dependIDs) && changeDependIDs) { 657 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 boolean previousRoot = root; 684 root = false; 685 outputComputedText(arg); 686 |