1 package net.sf.saxon.event; 2 import net.sf.saxon.expr.ExpressionLocation; 3 import net.sf.saxon.om.*; 4 import net.sf.saxon.trans.DynamicError; 5 import net.sf.saxon.trans.XPathException; 6 import net.sf.saxon.type.Type; 7 import net.sf.saxon.value.AtomicValue; 8 import net.sf.saxon.Configuration; 9 import net.sf.saxon.Err; 10 11 24 25 26 27 public final class ComplexContentOutputter extends SequenceReceiver { 28 29 private NamePool pool; 30 private Receiver receiver; 31 33 private int pendingStartTag = -2; 34 private int level = -1; private Boolean elementIsInNullNamespace; 40 private int[] pendingAttCode = new int[20]; 41 private int[] pendingAttType = new int[20]; 42 private CharSequence [] pendingAttValue = new String [20]; 43 private int[] pendingAttLocation = new int[20]; 44 private int[] pendingAttProp = new int[20]; 45 private int pendingAttListSize = 0; 46 47 private int[] pendingNSList = new int[20]; 48 private int pendingNSListSize = 0; 49 50 private int currentSimpleType = -1; 53 private int startElementProperties; 54 private int startElementLocationId; 55 private boolean declaresDefaultNamespace; 56 private boolean allowDuplicateAttributes; 57 58 public ComplexContentOutputter() {} 59 60 public void setPipelineConfiguration(PipelineConfiguration pipelineConfiguration) { 61 super.setPipelineConfiguration(pipelineConfiguration); 62 allowDuplicateAttributes = 63 pipelineConfiguration.getController().getExecutable().getHostLanguage() == Configuration.XSLT; 64 } 65 66 public NamePool getNamePool() { 67 if (pool == null) { 68 pool = super.getNamePool(); 69 } 70 return pool; 71 } 72 73 public void setSystemId(String systemId) {} 74 75 public String getSystemId() { 76 return null; 77 } 78 79 82 83 public void setReceiver(Receiver receiver) { 84 this.receiver = receiver; 85 } 86 87 90 91 public void open() throws XPathException { 92 receiver.open(); 93 previousAtomic = false; 94 } 95 96 99 100 public void startDocument(int properties) throws XPathException { 101 if (level < 0) { 102 receiver.startDocument(properties); 103 level = 0; 104 } else if (pendingStartTag >= 0) { 105 startContent(); 106 pendingStartTag = -2; 107 } 108 previousAtomic = false; 109 } 110 111 114 115 public void endDocument() throws XPathException { 116 if (level == 0) { 117 receiver.endDocument(); 118 level = -1; 119 } 120 } 121 122 123 130 131 public void characters(CharSequence s, int locationId, int properties) throws XPathException { 132 previousAtomic = false; 133 if (s==null) return; 134 int len = s.length(); 135 if (len==0) return; 136 if (pendingStartTag >= 0) { 137 startContent(); 138 } 139 receiver.characters(s, locationId, properties); 140 } 141 142 148 149 public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { 150 level++; 152 if (level == 0) { 153 level = 1; 154 } 155 156 if (pendingStartTag >= 0) { 157 startContent(); 158 } 159 startElementProperties = properties; 160 startElementLocationId = locationId; 161 pendingAttListSize = 0; 162 pendingNSListSize = 0; 163 pendingStartTag = nameCode; 164 elementIsInNullNamespace = null; currentSimpleType = typeCode; 166 previousAtomic = false; 167 } 168 169 170 180 181 public void namespace(int nscode, int properties) 182 throws XPathException { 183 184 if (pendingStartTag < 0) { 186 throw NoOpenStartTagException.makeNoOpenStartTagException( 187 Type.NAMESPACE, 188 getNamePool().getPrefix(nscode), 189 getPipelineConfiguration().getConfiguration().getHostLanguage(), 190 (level <= 0 || pendingStartTag == -2), 191 getPipelineConfiguration().isSerializing() && level <= 0 192 ); 193 } 194 195 198 200 boolean rejectDuplicates = (properties & ReceiverOptions.REJECT_DUPLICATES) != 0; 201 202 for (int i=0; i<pendingNSListSize; i++) { 203 if (nscode == pendingNSList[i]) { 204 return; 206 } 207 if ((nscode>>16) == (pendingNSList[i]>>16)) { 208 if (rejectDuplicates) { 209 DynamicError err = new DynamicError("Cannot create two namespace nodes with the same name"); 210 err.setErrorCode("XTDE0430"); 211 throw err; 212 } else { 213 return; 215 } 216 } 217 } 218 219 222 if (((nscode>>16) == 0) && ((nscode&0xffff)!=0)) { 223 declaresDefaultNamespace = true; 224 if (elementIsInNullNamespace == null) { 225 elementIsInNullNamespace = Boolean.valueOf( 226 getNamePool().getURI(pendingStartTag) == NamespaceConstant.NULL); 227 } 228 if (elementIsInNullNamespace.booleanValue()) { 229 DynamicError err = new DynamicError( 230 "Cannot output a namespace node for the default namespace when the element is in no namespace"); 231 err.setErrorCode("XTDE0440"); 232 throw err; 233 } 234 } 235 236 238 if (pendingNSListSize+1 > pendingNSList.length) { 239 int[] newlist = new int[pendingNSListSize * 2]; 240 System.arraycopy(pendingNSList, 0, newlist, 0, pendingNSListSize); 241 pendingNSList = newlist; 242 } 243 pendingNSList[pendingNSListSize++] = nscode; 244 previousAtomic = false; 245 } 246 247 248 259 260 public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { 261 263 if (pendingStartTag < 0) { 264 DynamicError err = NoOpenStartTagException.makeNoOpenStartTagException( 266 Type.ATTRIBUTE, 267 getNamePool().getDisplayName(nameCode), 268 getPipelineConfiguration().getConfiguration().getHostLanguage(), 269 (level<=0 || pendingStartTag == -2), 270 getPipelineConfiguration().isSerializing() && level <= 0); 271 err.setLocator(new ExpressionLocation( 272 getPipelineConfiguration().getLocationProvider(), 273 locationId)); 274 throw err; 275 } 276 277 280 for (int a=0; a<pendingAttListSize; a++) { 281 if ((pendingAttCode[a] & 0xfffff) == (nameCode & 0xfffff)) { 282 if (allowDuplicateAttributes) { 283 pendingAttType[a] = typeCode; 284 pendingAttValue[a] = value; 285 pendingAttLocation[a] = locationId; 286 pendingAttProp[a] = properties; 287 return; 288 } else { 289 DynamicError err = new DynamicError("Cannot create an element having two attributes with the same name: " + 290 Err.wrap(getNamePool().getDisplayName(nameCode), Err.ATTRIBUTE)); 291 err.setErrorCode("XQDY0025"); 292 throw err; 293 } 294 } 295 } 296 297 299 if (pendingAttListSize >= pendingAttCode.length) { 300 int[] attCode2 = new int[pendingAttListSize*2]; 301 int[] attType2 = new int[pendingAttListSize*2]; 302 String [] attValue2 = new String [pendingAttListSize*2]; 303 int[] attLoc2 = new int[pendingAttListSize*2]; 304 int[] attProp2 = new int[pendingAttListSize*2]; 305 System.arraycopy(pendingAttCode, 0, attCode2, 0, pendingAttListSize); 306 System.arraycopy(pendingAttType, 0, attType2, 0, pendingAttListSize); 307 System.arraycopy(pendingAttValue, 0, attValue2, 0, pendingAttListSize); 308 System.arraycopy(pendingAttLocation, 0, attLoc2, 0, pendingAttListSize); 309 System.arraycopy(pendingAttProp, 0, attProp2, 0, pendingAttListSize); 310 pendingAttCode = attCode2; 311 pendingAttType = attType2; 312 pendingAttValue = attValue2; 313 pendingAttLocation = attLoc2; 314 pendingAttProp = attProp2; 315 } 316 317 pendingAttCode[pendingAttListSize] = nameCode; 318 pendingAttType[pendingAttListSize] = typeCode; 319 pendingAttValue[pendingAttListSize] = value; 320 pendingAttLocation[pendingAttListSize] = locationId; 321 pendingAttProp[pendingAttListSize] = properties; 322 pendingAttListSize++; 323 previousAtomic = false; 324 } 325 326 333 334 private int checkProposedPrefix(int nameCode, int seq) throws XPathException { 335 NamePool namePool = getNamePool(); 336 int nscode = namePool.getNamespaceCode(nameCode); 337 if (nscode == -1) { 338 nscode = namePool.allocateNamespaceCode(nameCode); 340 } 341 int nsprefix = nscode>>16; 342 343 for (int i=0; i<pendingNSListSize; i++) { 344 if (nsprefix == (pendingNSList[i]>>16)) { 345 if ((nscode & 0xffff) == (pendingNSList[i] & 0xffff)) { 347 return nameCode; } else { 350 String prefix = getSubstitutePrefix(nscode, seq); 351 352 int newCode = namePool.allocate( 353 prefix, 354 namePool.getURI(nameCode), 355 namePool.getLocalName(nameCode)); 356 namespace(namePool.allocateNamespaceCode(newCode), 0); 357 return newCode; 358 } 359 } 360 } 361 namespace(nscode, 0); 363 return nameCode; 364 } 365 366 372 373 private String getSubstitutePrefix(int nscode, int seq) { 374 String prefix = getNamePool().getPrefixFromNamespaceCode(nscode); 375 return prefix + '_' + seq; 376 } 377 378 381 382 public void endElement() throws XPathException { 383 if (pendingStartTag >= 0) { 385 startContent(); 386 } 387 388 390 receiver.endElement(); 391 level--; 392 previousAtomic = false; 393 } 394 395 398 399 public void comment(CharSequence comment, int locationId, int properties) throws XPathException { 400 if (pendingStartTag >= 0) { 401 startContent(); 402 } 403 receiver.comment(comment, locationId, properties); 404 previousAtomic = false; 405 } 406 407 410 411 public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { 412 if (pendingStartTag >= 0) { 413 startContent(); 414 } 415 receiver.processingInstruction(target, data, locationId, properties); 416 previousAtomic = false; 417 } 418 419 425 426 public void append(Item item, int locationId, int copyNamespaces) throws XPathException { 427 if (item == null) { 428 return; 429 } else if (item instanceof AtomicValue) { 430 if (previousAtomic) { 431 characters(" ", locationId, 0); 432 } 433 characters(item.getStringValueCS(), locationId, 0); 434 previousAtomic = true; 435 } else if (item instanceof DocumentInfo) { 436 SequenceIterator iter = ((DocumentInfo)item).iterateAxis(Axis.CHILD); 437 while (true) { 438 Item it = iter.next(); 439 if (it == null) break; 440 append(it, locationId, copyNamespaces); 441 } 442 } else { 443 ((NodeInfo)item).copy(this, copyNamespaces, true, locationId); 444 previousAtomic = false; 445 } 446 } 447 448 449 452 453 public void close() throws XPathException { 454 receiver.close(); 456 previousAtomic = false; 457 } 458 459 462 463 public void startContent() throws XPathException { 464 465 if (pendingStartTag < 0) { 466 return; 469 } 470 471 int props = startElementProperties; 472 int elcode = pendingStartTag; 473 if (declaresDefaultNamespace || (elcode>>20 & 0xff) != 0) { 474 elcode = checkProposedPrefix(pendingStartTag, 0); 476 props = startElementProperties | ReceiverOptions.NAMESPACE_OK; 477 } 478 receiver.startElement(elcode, currentSimpleType, startElementLocationId, props); 479 480 for (int a=0; a<pendingAttListSize; a++) { 481 int attcode = pendingAttCode[a]; 482 if ((attcode>>20 & 0xff) != 0) { pendingAttCode[a] = checkProposedPrefix(attcode, a+1); 484 } 485 } 486 487 for (int n=0; n<pendingNSListSize; n++) { 488 receiver.namespace(pendingNSList[n], 0); 489 } 490 491 for (int a=0; a<pendingAttListSize; a++) { 492 receiver.attribute( pendingAttCode[a], 493 pendingAttType[a], 494 pendingAttValue[a], 495 pendingAttLocation[a], 496 pendingAttProp[a]); 497 } 498 499 receiver.startContent(); 500 501 pendingAttListSize = 0; 502 pendingNSListSize = 0; 503 pendingStartTag = -1; 504 previousAtomic = false; 505 } 506 507 } 508 509 | Popular Tags |