1 7 8 package org.cyberneko.html.filters; 9 10 import org.cyberneko.html.HTMLElements; 11 12 import java.lang.reflect.InvocationTargetException ; 13 import java.lang.reflect.Method ; 14 import java.util.Enumeration ; 15 import java.util.Vector ; 16 17 import org.apache.xerces.xni.Augmentations; 18 import org.apache.xerces.xni.NamespaceContext; 19 import org.apache.xerces.xni.QName; 20 import org.apache.xerces.xni.XMLAttributes; 21 import org.apache.xerces.xni.XMLLocator; 22 import org.apache.xerces.xni.XNIException; 23 import org.apache.xerces.xni.parser.XMLComponentManager; 24 import org.apache.xerces.xni.parser.XMLConfigurationException; 25 26 40 public class NamespaceBinder 41 extends DefaultFilter { 42 43 47 49 50 public static final String XHTML_1_0_URI = "http://www.w3.org/1999/xhtml"; 51 52 53 public static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; 54 55 56 public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; 57 58 60 61 protected static final String NAMESPACES = "http://xml.org/sax/features/namespaces"; 62 63 64 protected static final String OVERRIDE_NAMESPACES = "http://cyberneko.org/html/features/override-namespaces"; 65 66 67 protected static final String INSERT_NAMESPACES = "http://cyberneko.org/html/features/insert-namespaces"; 68 69 70 private static final String [] RECOGNIZED_FEATURES = { 71 NAMESPACES, 72 OVERRIDE_NAMESPACES, 73 INSERT_NAMESPACES, 74 }; 75 76 77 private static final Boolean [] FEATURE_DEFAULTS = { 78 null, 79 Boolean.FALSE, 80 Boolean.FALSE, 81 }; 82 83 85 86 protected static final String NAMES_ELEMS = "http://cyberneko.org/html/properties/names/elems"; 87 88 89 protected static final String NAMES_ATTRS = "http://cyberneko.org/html/properties/names/attrs"; 90 91 92 protected static final String NAMESPACES_URI = "http://cyberneko.org/html/properties/namespaces-uri"; 93 94 95 private static final String [] RECOGNIZED_PROPERTIES = new String [] { 96 NAMES_ELEMS, 97 NAMES_ATTRS, 98 NAMESPACES_URI, 99 }; 100 101 102 private static final Object [] PROPERTY_DEFAULTS = { 103 null, 104 null, 105 XHTML_1_0_URI, 106 }; 107 108 110 111 protected static final short NAMES_NO_CHANGE = 0; 112 113 114 protected static final short NAMES_UPPERCASE = 1; 115 116 117 protected static final short NAMES_LOWERCASE = 2; 118 119 123 125 126 protected boolean fNamespaces; 127 128 129 protected boolean fNamespacePrefixes; 130 131 132 protected boolean fOverrideNamespaces; 133 134 135 protected boolean fInsertNamespaces; 136 137 139 140 protected short fNamesElems; 141 142 143 protected short fNamesAttrs; 144 145 146 protected String fNamespacesURI; 147 148 150 151 protected final NamespaceSupport fNamespaceContext = new NamespaceSupport(); 152 153 155 156 private final QName fQName = new QName(); 157 158 162 167 public String [] getRecognizedFeatures() { 168 return merge(super.getRecognizedFeatures(), RECOGNIZED_FEATURES); 169 } 171 176 public Boolean getFeatureDefault(String featureId) { 177 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 178 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 179 return FEATURE_DEFAULTS[i]; 180 } 181 } 182 return super.getFeatureDefault(featureId); 183 } 185 190 public String [] getRecognizedProperties() { 191 return merge(super.getRecognizedProperties(), RECOGNIZED_PROPERTIES); 192 } 194 199 public Object getPropertyDefault(String propertyId) { 200 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 201 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 202 return PROPERTY_DEFAULTS[i]; 203 } 204 } 205 return super.getPropertyDefault(propertyId); 206 } 208 217 public void reset(XMLComponentManager manager) 218 throws XMLConfigurationException { 219 super.reset(manager); 220 221 fNamespaces = manager.getFeature(NAMESPACES); 223 fOverrideNamespaces = manager.getFeature(OVERRIDE_NAMESPACES); 224 fInsertNamespaces = manager.getFeature(INSERT_NAMESPACES); 225 226 fNamesElems = getNamesValue(String.valueOf(manager.getProperty(NAMES_ELEMS))); 228 fNamesAttrs = getNamesValue(String.valueOf(manager.getProperty(NAMES_ATTRS))); 229 fNamespacesURI = String.valueOf(manager.getProperty(NAMESPACES_URI)); 230 231 fNamespaceContext.reset(); 233 234 } 236 240 241 public void startDocument(XMLLocator locator, String encoding, 242 NamespaceContext nscontext, Augmentations augs) 243 throws XNIException { 244 245 super.startDocument(locator,encoding,fNamespaceContext,augs); 248 249 } 251 252 public void startElement(QName element, XMLAttributes attrs, 253 Augmentations augs) throws XNIException { 254 255 if (fNamespaces) { 257 fNamespaceContext.pushContext(); 258 bindNamespaces(element, attrs); 259 260 int dcount = fNamespaceContext.getDeclaredPrefixCount(); 261 if (fDocumentHandler != null && dcount > 0) { 262 try { 263 Class cls = fDocumentHandler.getClass(); 264 Class [] types = { String .class, String .class }; 265 Method method = cls.getMethod("startPrefixMapping", types); 266 for (int i = 0; i < dcount; i++) { 267 String prefix = fNamespaceContext.getDeclaredPrefixAt(i); 268 String uri = fNamespaceContext.getURI(prefix); 269 Object [] args = { prefix, uri }; 270 method.invoke(fDocumentHandler, args); 271 } 272 } 273 catch (NoSuchMethodException e) { 274 } 276 catch (InvocationTargetException e) { 277 } 279 catch (IllegalAccessException e) { 280 } 282 } 283 } 284 285 super.startElement(element, attrs, augs); 287 288 } 290 291 public void emptyElement(QName element, XMLAttributes attrs, 292 Augmentations augs) throws XNIException { 293 294 if (fNamespaces) { 296 fNamespaceContext.pushContext(); 297 bindNamespaces(element, attrs); 298 299 int dcount = fNamespaceContext.getDeclaredPrefixCount(); 300 if (fDocumentHandler != null && dcount > 0) { 301 try { 302 Class cls = fDocumentHandler.getClass(); 303 Class [] types = { String .class, String .class }; 304 Method method = cls.getMethod("startPrefixMapping", types); 305 for (int i = 0; i < dcount; i++) { 306 String prefix = fNamespaceContext.getDeclaredPrefixAt(i); 307 String uri = fNamespaceContext.getURI(prefix); 308 Object [] args = { prefix, uri }; 309 method.invoke(fDocumentHandler, args); 310 } 311 } 312 catch (NoSuchMethodException e) { 313 } 315 catch (InvocationTargetException e) { 316 } 318 catch (IllegalAccessException e) { 319 } 321 } 322 } 323 324 super.emptyElement(element, attrs, augs); 326 327 if (fNamespaces) { 329 int dcount = fNamespaceContext.getDeclaredPrefixCount(); 330 if (fDocumentHandler != null && dcount > 0) { 331 try { 332 Class cls = fDocumentHandler.getClass(); 333 Class [] types = { String .class }; 334 Method method = cls.getMethod("endPrefixMapping", types); 335 for (int i = dcount-1; i >= 0; i--) { 336 String prefix = fNamespaceContext.getDeclaredPrefixAt(i); 337 Object [] args = { prefix }; 338 method.invoke(fDocumentHandler, args); 339 } 340 } 341 catch (NoSuchMethodException e) { 342 } 344 catch (InvocationTargetException e) { 345 } 347 catch (IllegalAccessException e) { 348 } 350 } 351 352 fNamespaceContext.popContext(); 353 } 354 355 } 357 358 public void endElement(QName element, Augmentations augs) 359 throws XNIException { 360 361 if (fNamespaces) { 363 bindNamespaces(element, null); 364 } 365 366 super.endElement(element, augs); 368 369 if (fNamespaces) { 371 int dcount = fNamespaceContext.getDeclaredPrefixCount(); 372 if (fDocumentHandler != null && dcount > 0) { 373 try { 374 Class cls = fDocumentHandler.getClass(); 375 Class [] types = { String .class }; 376 Method method = cls.getMethod("endPrefixMapping", types); 377 for (int i = dcount-1; i >= 0; i--) { 378 String prefix = fNamespaceContext.getDeclaredPrefixAt(i); 379 Object [] args = { prefix }; 380 method.invoke(fDocumentHandler, args); 381 } 382 } 383 catch (NoSuchMethodException e) { 384 } 386 catch (InvocationTargetException e) { 387 } 389 catch (IllegalAccessException e) { 390 } 392 } 393 394 fNamespaceContext.popContext(); 395 } 396 397 } 399 403 404 protected static void splitQName(QName qname) { 405 int index = qname.rawname.indexOf(':'); 406 if (index != -1) { 407 qname.prefix = qname.rawname.substring(0,index); 408 qname.localpart = qname.rawname.substring(index+1); 409 } 410 } 412 419 protected static final short getNamesValue(String value) { 420 if (value.equals("lower")) { return NAMES_LOWERCASE; } 421 if (value.equals("upper")) { return NAMES_UPPERCASE; } 422 return NAMES_NO_CHANGE; 423 } 425 426 protected static final String modifyName(String name, short mode) { 427 switch (mode) { 428 case NAMES_UPPERCASE: return name.toUpperCase(); 429 case NAMES_LOWERCASE: return name.toLowerCase(); 430 } 431 return name; 432 } 434 438 439 protected void bindNamespaces(QName element, XMLAttributes attrs) { 440 441 splitQName(element); 443 444 int attrCount = attrs != null ? attrs.getLength() : 0; 446 for (int i = attrCount - 1; i >= 0; i--) { 447 attrs.getName(i, fQName); 448 String aname = fQName.rawname; 449 String ANAME = aname.toUpperCase(); 450 if (ANAME.startsWith("XMLNS:") || ANAME.equals("XMLNS")) { 451 int anamelen = aname.length(); 452 453 String aprefix = anamelen > 5 ? aname.substring(0,5) : null; 455 String alocal = anamelen > 5 ? aname.substring(6) : aname; 456 String avalue = attrs.getValue(i); 457 458 if (anamelen > 5) { 460 aprefix = modifyName(aprefix, NAMES_LOWERCASE); 461 alocal = modifyName(alocal, fNamesElems); 462 aname = aprefix + ':' + alocal; 463 } 464 else { 465 alocal = modifyName(alocal, NAMES_LOWERCASE); 466 aname = alocal; 467 } 468 fQName.setValues(aprefix, alocal, aname, null); 469 attrs.setName(i, fQName); 470 471 String prefix = alocal != aname ? alocal : ""; 473 String uri = avalue.length() > 0 ? avalue : null; 474 if (fOverrideNamespaces && 475 prefix.equals(element.prefix) && 476 HTMLElements.getElement(element.localpart, null) != null) { 477 uri = fNamespacesURI; 478 } 479 fNamespaceContext.declarePrefix(prefix, uri); 480 } 481 } 482 483 String prefix = element.prefix != null ? element.prefix : ""; 485 element.uri = fNamespaceContext.getURI(prefix); 486 if (element.uri != null && element.prefix == null) { 492 element.prefix = ""; 493 } 494 495 if (fInsertNamespaces && 497 HTMLElements.getElement(element.localpart,null) != null) { 498 if (element.prefix == null || 499 fNamespaceContext.getURI(element.prefix) == null) { 500 String xmlns = "xmlns" + ((element.prefix != null) 501 ? ":"+element.prefix : ""); 502 fQName.setValues(null, xmlns, xmlns, null); 503 attrs.addAttribute(fQName, "CDATA", fNamespacesURI); 504 bindNamespaces(element, attrs); 505 return; 506 } 507 } 508 509 attrCount = attrs != null ? attrs.getLength() : 0; 511 for (int i = 0; i < attrCount; i++) { 512 attrs.getName(i, fQName); 513 splitQName(fQName); 514 prefix = !fQName.rawname.equals("xmlns") 515 ? (fQName.prefix != null ? fQName.prefix : "") : "xmlns"; 516 if (!prefix.equals("")) { 518 fQName.uri = prefix.equals("xml") ? XML_URI : fNamespaceContext.getURI(prefix); 519 } 520 if (prefix.equals("xmlns") && fQName.uri == null) { 523 fQName.uri = XMLNS_URI; 524 } 525 attrs.setName(i, fQName); 526 } 527 528 } 530 534 539 public static class NamespaceSupport 540 implements NamespaceContext { 541 542 546 547 protected int fTop = 0; 548 549 550 protected int[] fLevels = new int[10]; 551 552 553 protected Entry[] fEntries = new Entry[10]; 554 555 559 560 public NamespaceSupport() { 561 pushContext(); 562 declarePrefix("xml", NamespaceContext.XML_URI); 563 declarePrefix("xmlns", NamespaceContext.XMLNS_URI); 564 } 566 570 572 573 public String getURI(String prefix) { 574 for (int i = fLevels[fTop]-1; i >= 0; i--) { 575 Entry entry = (Entry)fEntries[i]; 576 if (entry.prefix.equals(prefix)) { 577 return entry.uri; 578 } 579 } 580 return null; 581 } 583 584 public int getDeclaredPrefixCount() { 585 return fLevels[fTop] - fLevels[fTop-1]; 586 } 588 589 public String getDeclaredPrefixAt(int index) { 590 return fEntries[fLevels[fTop-1] + index].prefix; 591 } 593 594 public NamespaceContext getParentContext() { 595 return this; 596 } 598 600 601 public void reset() { 602 fLevels[fTop = 1] = fLevels[fTop-1]; 603 } 605 606 public void pushContext() { 607 if (++fTop == fLevels.length) { 608 int[] iarray = new int[fLevels.length + 10]; 609 System.arraycopy(fLevels, 0, iarray, 0, fLevels.length); 610 fLevels = iarray; 611 } 612 fLevels[fTop] = fLevels[fTop-1]; 613 } 615 616 public void popContext() { 617 fTop--; 618 } 620 621 public boolean declarePrefix(String prefix, String uri) { 622 int count = getDeclaredPrefixCount(); 623 for (int i = 0; i < count; i++) { 624 String dprefix = getDeclaredPrefixAt(i); 625 if (dprefix.equals(prefix)) { 626 return false; 627 } 628 } 629 Entry entry = new Entry(prefix, uri); 630 if (fLevels[fTop] == fEntries.length) { 631 Entry[] earray = new Entry[fEntries.length + 10]; 632 System.arraycopy(fEntries, 0, earray, 0, fEntries.length); 633 fEntries = earray; 634 } 635 fEntries[fLevels[fTop]++] = entry; 636 return true; 637 } 639 640 public String getPrefix(String uri) { 641 for (int i = fLevels[fTop]-1; i >= 0; i--) { 642 Entry entry = (Entry)fEntries[i]; 643 if (entry.uri.equals(uri)) { 644 return entry.prefix; 645 } 646 } 647 return null; 648 } 650 651 public Enumeration getAllPrefixes() { 652 Vector prefixes = new Vector (); 653 for (int i = fLevels[1]; i < fLevels[fTop]; i++) { 654 String prefix = fEntries[i].prefix; 655 if (!prefixes.contains(prefix)) { 656 prefixes.addElement(prefix); 657 } 658 } 659 return prefixes.elements(); 660 } 662 666 667 static class Entry { 668 669 673 674 public String prefix; 675 676 677 public String uri; 678 679 683 684 public Entry(String prefix, String uri) { 685 this.prefix = prefix; 686 this.uri = uri; 687 } 689 } 691 } 693 } | Popular Tags |