1 10 package org.mmbase.util.xml; 11 12 import java.util.*; 13 import java.util.regex.Pattern ; 14 15 import org.xml.sax.ErrorHandler ; 16 import org.xml.sax.EntityResolver ; 17 import org.xml.sax.InputSource ; 18 19 import org.w3c.dom.*; 20 21 import javax.xml.parsers.DocumentBuilder ; 22 import javax.xml.parsers.DocumentBuilderFactory ; 23 import javax.xml.parsers.ParserConfigurationException ; 24 25 import org.mmbase.util.XMLEntityResolver; 26 import org.mmbase.util.XMLErrorHandler; 27 28 import org.mmbase.util.logging.Logging; 29 import org.mmbase.util.logging.Logger; 30 31 46 public class DocumentReader { 47 private static Logger log = Logging.getLoggerInstance(DocumentReader.class); 48 49 50 private static Map documentBuilders = Collections.synchronizedMap(new HashMap()); 51 52 protected static final String FILENOTFOUND = "FILENOTFOUND://"; 53 54 55 public static final String PUBLIC_ID_ERROR_1_0 = "-//MMBase//DTD error 1.0//EN"; 56 57 public static final String DTD_ERROR_1_0 = "error_1_0.dtd"; 58 59 60 public static final String PUBLIC_ID_ERROR = PUBLIC_ID_ERROR_1_0; 61 62 public static final String DTD_ERROR = DTD_ERROR_1_0; 63 64 68 public static void registerPublicIDs() { 69 XMLEntityResolver.registerPublicID(PUBLIC_ID_ERROR_1_0, DTD_ERROR_1_0, DocumentReader.class); 70 } 71 72 protected Document document; 73 74 private String systemId; 75 76 static UtilReader.PropertiesMap utilProperties = null; 77 81 protected static final boolean validate() { 82 Object validate = utilProperties == null ? null : utilProperties.get("validate"); 83 return validate == null || validate.equals("true"); 84 } 85 86 90 protected static final boolean validate(boolean requested) { 91 Object validate = utilProperties == null ? null : utilProperties.get("validate"); 92 if (validate != null && validate.equals("never")) return false; 93 return requested; 94 } 95 96 97 100 protected DocumentReader() { 101 } 102 103 107 public DocumentReader(InputSource source) { 108 this(source, validate(), null); 109 } 110 111 116 public DocumentReader(InputSource source, boolean validating) { 117 this(source, validating, null); 118 } 119 120 127 public DocumentReader(InputSource source, Class resolveBase) { 128 this(source, DocumentReader.validate(), resolveBase); 129 } 130 131 139 public DocumentReader(InputSource source, boolean validating, Class resolveBase) { 140 if (source == null) { 141 throw new IllegalArgumentException ("InputSource cannot be null"); 142 } 143 try { 144 systemId = source.getSystemId(); 145 XMLEntityResolver resolver = null; 146 if (resolveBase != null) resolver = new XMLEntityResolver(validating, resolveBase); 147 DocumentBuilder dbuilder = getDocumentBuilder(validating, null, resolver); 148 if(dbuilder == null) throw new RuntimeException ("failure retrieving document builder"); 149 if (log.isDebugEnabled()) log.debug("Reading " + source.getSystemId()); 150 document = dbuilder.parse(source); 151 } catch(org.xml.sax.SAXException se) { 152 throw new RuntimeException ("failure reading document: " + source.getSystemId() + "\n" + Logging.stackTrace(se)); 153 } catch(java.io.IOException ioe) { 154 throw new RuntimeException ("failure reading document: " + source.getSystemId() + "\n" + ioe, ioe); 155 } 156 } 157 158 161 public DocumentReader(Document doc) { 162 document = doc; 163 } 164 165 166 private static boolean warnedJAXP12 = false; 167 175 private static DocumentBuilder createDocumentBuilder(boolean validating, boolean xsd, ErrorHandler handler, EntityResolver resolver) { 176 DocumentBuilder db; 177 if (handler == null) handler = new XMLErrorHandler(); 178 if (resolver == null) resolver = new XMLEntityResolver(validating); 179 try { 180 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 182 dfactory.setValidating(validating); 184 if (validating && xsd) { 185 try { 186 dfactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", 187 "http://www.w3.org/2001/XMLSchema"); 188 } catch (IllegalArgumentException iae) { 189 if (! warnedJAXP12) { 190 log.warn("The XML parser does not support JAXP 1.2, XSD validation will not work.", iae); 191 warnedJAXP12 = true; 192 } 193 } 194 } 195 dfactory.setNamespaceAware(true); 196 197 db = dfactory.newDocumentBuilder(); 198 199 db.setErrorHandler(handler); 200 201 db.setEntityResolver(resolver); 203 204 } catch(ParserConfigurationException pce) { 205 log.error("a DocumentBuilder cannot be created which satisfies the configuration requested"); 206 log.error(Logging.stackTrace(pce)); 207 return null; 208 } 209 return db; 210 } 211 212 217 public static DocumentBuilder getDocumentBuilder() { 218 return getDocumentBuilder(validate(), null, null); 219 } 220 221 222 225 public static DocumentBuilder getDocumentBuilder(boolean validating) { 226 return DocumentReader.getDocumentBuilder(validating, null, null); 227 } 228 229 232 public static DocumentBuilder getDocumentBuilder(boolean validating, ErrorHandler handler, EntityResolver resolver) { 233 return getDocumentBuilder(validating, false, handler, resolver); 234 } 235 236 247 public static DocumentBuilder getDocumentBuilder(boolean validating, boolean xsd, ErrorHandler handler, EntityResolver resolver) { 248 validating = validate(validating); 249 if (handler == null && resolver == null) { 250 String key = "" + validating + xsd; 251 DocumentBuilder db = (DocumentBuilder ) documentBuilders.get(key); 252 if (db == null) { 253 db = createDocumentBuilder(validating, xsd, null, null); 254 documentBuilders.put(key, db); 255 } 256 return db; 257 } else { 258 return createDocumentBuilder(validating, xsd, handler, resolver); 259 } 260 } 261 262 271 public static String getNodeTextValue(Node n) { 272 NodeList nl = n.getChildNodes(); 273 StringBuffer res = new StringBuffer (); 274 for (int i = 0; i < nl.getLength(); i++) { 275 Node textnode = nl.item(i); 276 if (textnode.getNodeType() == Node.TEXT_NODE) { 277 res.append(textnode.getNodeValue().trim()); 278 } else if (textnode.getNodeType() == Node.CDATA_SECTION_NODE) { 279 res.append(textnode.getNodeValue()); 280 } 281 } 282 return res.toString(); 283 } 284 285 288 public static void setNodeTextValue(Node n, String value) { 289 NodeList textNodes = n.getChildNodes(); 290 for (int j = 0; j < textNodes.getLength(); j++) { 291 n.removeChild(textNodes.item(j)); 292 } 293 Text text = n.getOwnerDocument().createTextNode(value); 294 n.appendChild(text); 295 } 296 297 301 static public boolean hasAttribute(Element element, String nameSpace, String localName) { 302 return element.hasAttributeNS(nameSpace,localName) || element.hasAttribute(localName); 303 } 304 305 309 static public String getAttribute(Element element, String nameSpace, String localName) { 310 if (element.hasAttributeNS(nameSpace, localName)) { 311 return element.getAttributeNS(nameSpace, localName); 312 } else { 313 return element.getAttribute(localName); 314 } 315 } 316 317 321 static public Document toDocument(Element element) { 322 DocumentBuilder documentBuilder = getDocumentBuilder(false, null, null); 323 DOMImplementation impl = documentBuilder.getDOMImplementation(); 324 Document document = impl.createDocument(element.getNamespaceURI(), element.getLocalName(), null); 325 Element dest = document.getDocumentElement(); 326 Element copy = (Element) document.importNode(element, false); 327 NamedNodeMap attributes = copy.getAttributes(); 328 for (int i = 0; i < attributes.getLength(); i++) { 329 Attr attribute = (Attr) (attributes.item(i).cloneNode(true)); 330 dest.setAttributeNode(attribute); 331 332 } 333 NodeList childs = element.getChildNodes(); 334 for (int i = 0; i < childs.getLength() ; i++) { 335 Node child = document.importNode(childs.item(i), true); 336 dest.appendChild(child); 337 } 338 document.normalize(); 339 return document; 340 } 341 342 343 354 static public void appendChild(Element parent, Element newChild, String path) { 355 String [] p = path.split(","); 356 int i = 0; 357 Node refChild = null; 358 NodeList childs = parent.getChildNodes(); 359 int j = 0; 360 Pattern pattern = null; 361 if (p.length > 0) pattern = Pattern.compile("\\A" + p[i] + "\\z"); 362 boolean matching = false; 363 while (j < childs.getLength() && i < p.length) { 364 if (childs.item(j) instanceof Element) { 365 Element child = (Element) childs.item(j); 366 if (pattern.matcher(child.getTagName()).matches()) { 367 j++; 368 refChild = childs.item(j); 369 matching = true; 370 } else { 371 if (! matching) { refChild = childs.item(j); 373 break; 374 } 375 i++; 376 pattern = i < p.length ? Pattern.compile("\\A" + p[i] + "\\z") : null; 377 } 378 } else { 379 j++; 380 } 381 } 382 parent.insertBefore(newChild, refChild); 383 } 384 385 392 public String getSystemId() { 393 return systemId; 394 } 395 396 399 public void setSystemId(String url) { 400 systemId = url; 401 } 402 403 407 public String getElementName(Element e) { 408 return e.getLocalName(); 409 } 410 411 416 public String getElementAttributeValue(String path, String attr) { 417 return getElementAttributeValue(getElementByPath(path),attr); 418 } 419 420 421 426 public String getElementAttributeValue(Element e, String attr) { 427 if (e == null) { 428 return ""; 429 } else { 430 return e.getAttribute(attr); 431 } 432 } 433 434 439 public Element getRootElement() { 440 if (document == null) { 441 log.error("Document is not defined, cannot get root element"); 442 } 443 return document.getDocumentElement(); 444 } 445 446 451 public Element getElementByPath(String path) { 452 if (document == null) { 453 log.error("Document is not defined, cannot get " + path); 454 } 455 return getElementByPath(document.getDocumentElement(),path); 456 } 457 458 464 public Element getElementByPath(Element e, String path) { 465 StringTokenizer st = new StringTokenizer(path,"."); 466 if (!st.hasMoreTokens()) { 467 log.error("No tokens in path"); 469 return null; 470 } else { 471 String root = st.nextToken(); 472 if (e.getLocalName().equals("error")) { 473 log.error("Error occurred : (" + getElementValue(e) + ")"); 475 return null; 476 } else if (!e.getLocalName().equals(root)) { 477 log.error("path ["+path+"] with root ("+root+") doesn't start with root element ("+e.getLocalName()+"): incorrect xml file" + 479 "("+getSystemId()+")"); 480 return null; 481 } 482 OUTER: 483 while (st.hasMoreTokens()) { 484 String tag = st.nextToken(); 485 NodeList nl = e.getChildNodes(); 486 for(int i = 0; i < nl.getLength(); i++) { 487 if (! (nl.item(i) instanceof Element)) continue; 488 e = (Element)nl.item(i); 489 if (e.getLocalName().equals(tag)) continue OUTER; 490 } 491 return null; 493 } 494 return e; 495 } 496 } 497 498 499 503 public String getElementValue(String path) { 504 return getElementValue(getElementByPath(path)); 505 } 506 507 511 public String getElementValue(Element e) { 512 if (e == null) { 513 return ""; 514 } else { 515 return getNodeTextValue(e); 516 } 517 } 518 519 523 public Iterator getChildElements(String path) { 524 return getChildElements(getElementByPath(path)); 525 } 526 527 531 public Iterator getChildElements(Element e) { 532 return getChildElements(e,"*"); 533 } 534 535 540 public Iterator getChildElements(String path,String tag) { 541 return getChildElements(getElementByPath(path),tag); 542 } 543 544 550 public Iterator getChildElements(Element e,String tag) { 551 List v = new ArrayList(); 552 boolean ignoretag = tag.equals("*"); 553 if (e!=null) { 554 NodeList nl = e.getChildNodes(); 555 for (int i = 0; i < nl.getLength(); i++) { 556 Node n = nl.item(i); 557 if (n.getNodeType() == Node.ELEMENT_NODE && 558 (ignoretag || 559 ((Element)n).getLocalName().equalsIgnoreCase(tag))) { 560 v.add(n); 561 } 562 } 563 } 564 return v.iterator(); 565 } 566 567 public static void main(String [] argv) throws Exception { 568 if (argv.length == 0) { 569 System.out.println("Usage: java -Dmmbase.config=<config dir> org.mmbase.util.xml.DocumentReader <path to xml>"); 570 System.out.println(" The mmbase config dir is used to resolve XSD's (in config/xmlns) and DTD's (in config/dtd)."); 571 System.out.println(" Errors will be reported if the XML is invalid"); 572 573 return; 574 } 575 Document d = org.mmbase.util.ResourceLoader.getDocument(new java.io.File (argv[0]).toURL(), true, null); 576 580 } 581 582 } 583
| Popular Tags
|