1 31 32 package org.opencms.xml; 33 34 import org.opencms.file.CmsResource; 35 import org.opencms.main.CmsLog; 36 import org.opencms.util.CmsStringUtil; 37 38 import java.io.ByteArrayInputStream ; 39 import java.io.ByteArrayOutputStream ; 40 import java.io.IOException ; 41 import java.io.OutputStream ; 42 import java.io.StringReader ; 43 import java.io.StringWriter ; 44 import java.io.UnsupportedEncodingException ; 45 import java.util.List ; 46 47 import org.apache.commons.logging.Log; 48 49 import org.dom4j.Document; 50 import org.dom4j.DocumentException; 51 import org.dom4j.Node; 52 import org.dom4j.io.OutputFormat; 53 import org.dom4j.io.SAXReader; 54 import org.dom4j.io.XMLWriter; 55 import org.xml.sax.EntityResolver ; 56 import org.xml.sax.InputSource ; 57 import org.xml.sax.SAXException ; 58 import org.xml.sax.SAXNotRecognizedException ; 59 import org.xml.sax.SAXNotSupportedException ; 60 import org.xml.sax.XMLReader ; 61 import org.xml.sax.helpers.XMLReaderFactory ; 62 63 72 public final class CmsXmlUtils { 73 74 75 private static final Log LOG = CmsLog.getLog(CmsXmlUtils.class); 76 77 80 private CmsXmlUtils() { 81 82 } 84 85 101 public static String concatXpath(String prefix, String suffix) { 102 103 if (suffix == null) { 104 suffix = ""; 106 } else { 107 if ((suffix.length() > 0) && (suffix.charAt(0) == '/')) { 108 suffix = suffix.substring(1); 110 } 111 } 112 if (prefix != null) { 113 StringBuffer result = new StringBuffer (32); 114 result.append(prefix); 115 if (!CmsResource.isFolder(prefix)) { 116 result.append('/'); 117 } 118 result.append(suffix); 119 return result.toString(); 120 } 121 return suffix; 122 } 123 124 142 public static String createXpath(String path, int index) { 143 144 if (path.indexOf('/') > -1) { 145 StringBuffer result = new StringBuffer (path.length() + 32); 147 148 List elements = CmsStringUtil.splitAsList(path, '/'); 150 int end = elements.size() - 1; 151 for (int i = 0; i <= end; i++) { 152 result.append(createXpathElementCheck((String )elements.get(i), (i == end) ? index : 1)); 154 if (i < end) { 155 result.append('/'); 157 } 158 } 159 return result.toString(); 160 } 161 162 return createXpathElementCheck(path, index); 164 } 165 166 178 public static String createXpathElement(String path, int index) { 179 180 StringBuffer result = new StringBuffer (path.length() + 5); 181 result.append(path); 182 result.append('['); 183 result.append(index); 184 result.append(']'); 185 return result.toString(); 186 } 187 188 202 public static String createXpathElementCheck(String path, int index) { 203 204 if (path.charAt(path.length() - 1) == ']') { 205 return path; 208 } 209 210 return createXpathElement(path, index); 212 } 213 214 228 public static String getFirstXpathElement(String path) { 229 230 int pos = path.indexOf('/'); 231 if (pos >= 0) { 232 path = path.substring(0, pos); 233 } 234 235 return CmsXmlUtils.removeXpathIndex(path); 236 } 237 238 252 public static String getLastXpathElement(String path) { 253 254 int pos = path.lastIndexOf('/'); 255 if (pos >= 0) { 256 path = path.substring(pos + 1); 257 } 258 259 return CmsXmlUtils.removeXpathIndex(path); 260 } 261 262 275 public static String getXpathIndex(String path) { 276 277 int pos1 = path.lastIndexOf('/'); 278 int pos2 = path.lastIndexOf('['); 279 if ((pos2 < 0) || (pos1 > pos2)) { 280 return ""; 281 } 282 283 return path.substring(pos2); 284 } 285 286 299 public static boolean isDeepXpath(String path) { 300 301 return path.indexOf('/') > 0; 302 } 303 304 313 public static OutputStream marshal(Document document, OutputStream out, String encoding) throws CmsXmlException { 314 315 try { 316 OutputFormat format = OutputFormat.createPrettyPrint(); 317 format.setEncoding(encoding); 318 319 XMLWriter writer = new XMLWriter(out, format); 320 writer.setEscapeText(false); 321 322 writer.write(document); 323 writer.close(); 324 325 } catch (Exception e) { 326 throw new CmsXmlException(Messages.get().container(Messages.ERR_MARSHALLING_XML_DOC_0), e); 327 } 328 329 return out; 330 } 331 332 340 public static String marshal(Document document, String encoding) throws CmsXmlException { 341 342 ByteArrayOutputStream out = new ByteArrayOutputStream (); 343 marshal(document, out, encoding); 344 try { 345 return out.toString(encoding); 346 } catch (UnsupportedEncodingException e) { 347 throw new CmsXmlException(Messages.get().container(Messages.ERR_MARSHALLING_XML_DOC_TO_STRING_0), e); 348 } 349 } 350 351 361 public static String marshal(Node node, String encoding) throws CmsXmlException { 362 363 ByteArrayOutputStream out = new ByteArrayOutputStream (); 364 try { 365 OutputFormat format = OutputFormat.createPrettyPrint(); 366 format.setEncoding(encoding); 367 format.setSuppressDeclaration(true); 368 369 XMLWriter writer = new XMLWriter(out, format); 370 writer.setEscapeText(false); 371 372 writer.write(node); 373 writer.close(); 374 } catch (Exception e) { 375 throw new CmsXmlException(Messages.get().container(Messages.ERR_MARSHALLING_XML_DOC_0), e); 376 } 377 return new String (out.toByteArray()); 378 } 379 380 396 public static String removeFirstXpathElement(String path) { 397 398 int pos = path.indexOf('/'); 399 if (pos < 0) { 400 return path; 401 } 402 403 return path.substring(pos + 1); 404 } 405 406 422 public static String removeLastXpathElement(String path) { 423 424 int pos = path.lastIndexOf('/'); 425 if (pos < 0) { 426 return path; 427 } 428 429 return path.substring(0, pos); 430 } 431 432 444 public static String removeLastComplexXpathElement(String path) { 445 446 int pos = path.lastIndexOf('/'); 447 if (pos < 0) { 448 return path; 449 } 450 int p = pos; 452 int count = -1; 453 while (p > 0) { 454 count++; 455 p = path.indexOf("\'", p + 1); 456 } 457 String parentPath = path.substring(0, pos); 458 if (count % 2 == 0) { 459 return parentPath; 461 } 462 p = parentPath.lastIndexOf("'"); 464 if (p >= 0) { 465 return removeLastComplexXpathElement(parentPath.substring(0, p)); 467 } 468 return parentPath; 469 } 470 471 484 public static String removeXpath(String path) { 485 486 if (path.indexOf('/') > -1) { 487 StringBuffer result = new StringBuffer (path.length() + 32); 489 490 List elements = CmsStringUtil.splitAsList(path, '/'); 492 int end = elements.size() - 1; 493 for (int i = 0; i <= end; i++) { 494 result.append(removeXpathIndex((String )elements.get(i))); 496 if (i < end) { 497 result.append('/'); 499 } 500 } 501 return result.toString(); 502 } 503 504 return removeXpathIndex(path); 506 } 507 508 521 public static String removeXpathIndex(String path) { 522 523 int pos1 = path.lastIndexOf('/'); 524 int pos2 = path.lastIndexOf('['); 525 if ((pos2 < 0) || (pos1 > pos2)) { 526 return path; 527 } 528 529 return path.substring(0, pos2); 530 } 531 532 544 public static String simplifyXpath(String path) { 545 546 StringBuffer result = new StringBuffer (path); 547 if (result.charAt(0) == '/') { 548 result.deleteCharAt(0); 549 } 550 int pos = result.length() - 1; 551 if (result.charAt(pos) == '/') { 552 result.deleteCharAt(pos); 553 } 554 return result.toString(); 555 } 556 557 568 public static Document unmarshalHelper(byte[] xmlData, EntityResolver resolver) throws CmsXmlException { 569 570 return CmsXmlUtils.unmarshalHelper(new InputSource (new ByteArrayInputStream (xmlData)), resolver); 571 } 572 573 588 public static Document unmarshalHelper(InputSource source, EntityResolver resolver) throws CmsXmlException { 589 590 try { 591 SAXReader reader = new SAXReader(); 592 if (resolver != null) { 593 reader.setEntityResolver(resolver); 594 } 595 reader.setMergeAdjacentText(true); 596 reader.setStripWhitespaceText(true); 597 return reader.read(source); 598 } catch (DocumentException e) { 599 throw new CmsXmlException(Messages.get().container(Messages.ERR_UNMARSHALLING_XML_DOC_0), e); 600 } 601 } 602 603 614 public static Document unmarshalHelper(String xmlData, EntityResolver resolver) throws CmsXmlException { 615 616 return CmsXmlUtils.unmarshalHelper(new InputSource (new StringReader (xmlData)), resolver); 617 } 618 619 628 public static void validateXmlStructure(byte[] xmlData, EntityResolver resolver) throws CmsXmlException { 629 630 XMLReader reader; 631 try { 632 reader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); 633 } catch (SAXException e) { 634 if (LOG.isWarnEnabled()) { 636 LOG.warn(Messages.get().getBundle().key(Messages.LOG_VALIDATION_INIT_XERXES_SAX_READER_FAILED_0), e); 637 } 638 return; 640 } 641 try { 643 reader.setFeature("http://xml.org/sax/features/validation", true); 644 reader.setFeature("http://apache.org/xml/features/validation/schema", true); 646 reader.setFeature("http://xml.org/sax/features/namespaces", true); 648 reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false); 649 } catch (SAXNotRecognizedException e) { 650 if (LOG.isWarnEnabled()) { 652 LOG.warn(Messages.get().getBundle().key(Messages.LOG_SAX_READER_FEATURE_NOT_RECOGNIZED_0), e); 653 } 654 return; 656 } catch (SAXNotSupportedException e) { 657 if (LOG.isWarnEnabled()) { 659 LOG.warn(Messages.get().getBundle().key(Messages.LOG_SAX_READER_FEATURE_NOT_SUPPORTED_0), e); 660 } 661 return; 663 } 664 665 CmsXmlValidationErrorHandler errorHandler = new CmsXmlValidationErrorHandler(); 667 reader.setErrorHandler(errorHandler); 668 669 if (resolver != null) { 670 reader.setEntityResolver(resolver); 672 } 673 674 try { 675 reader.parse(new InputSource (new ByteArrayInputStream (xmlData))); 676 } catch (IOException e) { 677 if (LOG.isErrorEnabled()) { 679 LOG.error(Messages.get().getBundle().key(Messages.LOG_READ_XML_FROM_BYTE_ARR_FAILED_0), e); 680 } 681 return; 682 } catch (SAXException e) { 683 if (LOG.isErrorEnabled()) { 685 LOG.error(Messages.get().getBundle().key(Messages.LOG_PARSE_SAX_EXC_0), e); 686 } 687 return; 688 } 689 690 if (errorHandler.getErrors().elements().size() > 0) { 691 StringWriter out = new StringWriter (256); 693 OutputFormat format = OutputFormat.createPrettyPrint(); 694 XMLWriter writer = new XMLWriter(out, format); 695 try { 696 writer.write(errorHandler.getErrors()); 697 writer.write(errorHandler.getWarnings()); 698 writer.close(); 699 } catch (IOException e) { 700 if (LOG.isErrorEnabled()) { 702 LOG.error(Messages.get().getBundle().key(Messages.LOG_STRINGWRITER_IO_EXC_0), e); 703 } 704 } 705 throw new CmsXmlException(Messages.get().container(Messages.ERR_XML_VALIDATION_1, out.toString())); 707 } 708 } 709 710 720 public static void validateXmlStructure(Document document, String encoding, EntityResolver resolver) 721 throws CmsXmlException { 722 723 byte[] xmlData = ((ByteArrayOutputStream )marshal(document, new ByteArrayOutputStream (512), encoding)).toByteArray(); 725 validateXmlStructure(xmlData, resolver); 726 } 727 } | Popular Tags |