1 18 package org.enhydra.convert.xml; 19 20 import java.io.File ; 22 import java.io.FileReader ; 23 import java.io.FileWriter ; 24 import java.io.InputStream ; 25 import java.io.InputStreamReader ; 26 import java.io.IOException ; 27 import java.io.OutputStream ; 28 import java.io.OutputStreamWriter ; 29 import java.io.Reader ; 30 import java.io.Writer ; 31 import java.util.HashMap ; 32 import java.util.Iterator ; 33 import java.util.Map ; 34 import org.xml.sax.EntityResolver ; 35 import org.xml.sax.ErrorHandler ; 36 import org.xml.sax.InputSource ; 37 import org.xml.sax.Locator ; 38 import org.xml.sax.SAXException ; 39 import org.xml.sax.SAXParseException ; 40 import org.xml.sax.XMLReader ; 41 import org.xml.sax.ext.LexicalHandler ; 42 import org.xml.sax.helpers.DefaultHandler ; 43 import org.xml.sax.helpers.XMLReaderFactory ; 44 45 public class DistributableImpl extends DefaultHandler implements Cloneable , Unmarshallable, LexicalHandler , Distributable { 46 47 private String id; 48 private boolean zeus_IdSet; 49 50 51 private String docTypeString; 52 53 54 private String outputEncoding; 55 56 57 private Unmarshallable zeus_currentUNode; 58 59 60 private Unmarshallable zeus_parentUNode; 61 62 63 private boolean zeus_thisNodeHandled = false; 64 65 66 private boolean hasDTD; 67 68 69 private boolean validate; 70 71 72 private Map namespaceMappings; 73 74 75 private static EntityResolver entityResolver; 76 77 78 private static ErrorHandler errorHandler; 79 80 private static DistributableImpl prototype = null; 81 82 public static void setPrototype(DistributableImpl prototype) { 83 DistributableImpl.prototype = prototype; 84 } 85 public static DistributableImpl newInstance() { 86 try { 87 return (prototype!=null)?(DistributableImpl)prototype.clone(): new DistributableImpl(); 88 } catch (CloneNotSupportedException e) { 89 return null; } 91 } 92 public DistributableImpl() { 93 zeus_IdSet = false; 94 docTypeString = ""; 95 hasDTD = false; 96 validate = false; 97 namespaceMappings = new HashMap (); 98 } 99 100 public String getId() { 101 return id; 102 } 103 104 public void setId(String id) { 105 this.id = id; 106 zeus_IdSet = true; 107 } 108 109 public void setDocType(String name, String publicID, String systemID) { 110 try { 111 startDTD(name, publicID, systemID); 112 } catch (SAXException neverHappens) { } 113 } 114 115 public void setOutputEncoding(String outputEncoding) { 116 this.outputEncoding = outputEncoding; 117 } 118 119 public void marshal(File file) throws IOException { 120 marshal(new FileWriter (file)); 122 } 123 124 public void marshal(OutputStream outputStream) throws IOException { 125 marshal(new OutputStreamWriter (outputStream)); 127 } 128 129 public void marshal(Writer writer) throws IOException { 130 writer.write("<?xml version=\"1.0\" "); 132 if (outputEncoding != null) { 133 writer.write("encoding=\""); 134 writer.write(outputEncoding); 135 writer.write("\"?>\n\n"); 136 137 } else { 138 writer.write("encoding=\"UTF-8\"?>\n\n"); 139 140 } 141 writer.write(docTypeString); 143 writer.write("\n"); 144 writeXMLRepresentation(writer, ""); 146 147 writer.flush(); 149 writer.close(); 150 } 151 152 protected void writeXMLRepresentation(Writer writer, 153 String indent) 154 throws IOException { 155 156 writer.write(indent); 157 writer.write("<distributable"); 158 159 for (Iterator i = namespaceMappings.keySet().iterator(); i.hasNext(); ) { 161 String prefix = (String )i.next(); 162 String uri = (String )namespaceMappings.get(prefix); 163 writer.write(" xmlns"); 164 if (!prefix.trim().equals("")) { 165 writer.write(":"); 166 writer.write(prefix); 167 } 168 writer.write("=\""); 169 writer.write(uri); 170 writer.write("\"\n "); 171 } 172 173 if (zeus_IdSet) { 175 writer.write(" id=\""); 176 writer.write(escapeAttributeValue(id)); 177 writer.write("\""); 178 } 179 writer.write("/>\n"); 180 } 181 182 private String escapeAttributeValue(String attributeValue) { 183 String returnValue = attributeValue; 184 for (int i = 0; i < returnValue.length(); i++) { 185 char ch = returnValue.charAt(i); 186 if (ch == '"') { 187 returnValue = new StringBuffer () 188 .append(returnValue.substring(0, i)) 189 .append(""") 190 .append(returnValue.substring(i+1)) 191 .toString(); 192 } 193 } 194 return returnValue; 195 } 196 197 private String escapeTextValue(String textValue) { 198 String returnValue = textValue; 199 for (int i = 0; i < returnValue.length(); i++) { 200 char ch = returnValue.charAt(i); 201 if (ch == '<') { 202 returnValue = new StringBuffer () 203 .append(returnValue.substring(0, i)) 204 .append("<") 205 .append(returnValue.substring(i+1)) 206 .toString(); 207 } else if (ch == '>') { 208 returnValue = new StringBuffer () 209 .append(returnValue.substring(0, i)) 210 .append(">") 211 .append(returnValue.substring(i+1)) 212 .toString(); 213 } 214 } 215 return returnValue; 216 } 217 218 225 public static void setEntityResolver(EntityResolver resolver) { 226 entityResolver = resolver; 227 } 228 229 236 public static void setErrorHandler(ErrorHandler handler) { 237 errorHandler = handler; 238 } 239 240 public static Distributable unmarshal(File file) throws IOException { 241 return unmarshal(new FileReader (file)); 243 } 244 245 public static Distributable unmarshal(File file, boolean validate) throws IOException { 246 return unmarshal(new FileReader (file), validate); 248 } 249 250 public static Distributable unmarshal(InputStream inputStream) throws IOException { 251 return unmarshal(new InputStreamReader (inputStream)); 253 } 254 255 public static Distributable unmarshal(InputStream inputStream, boolean validate) throws IOException { 256 return unmarshal(new InputStreamReader (inputStream), validate); 258 } 259 260 public static Distributable unmarshal(Reader reader) throws IOException { 261 return unmarshal(reader, false); 263 } 264 265 public static Distributable unmarshal(Reader reader, boolean validate) throws IOException { 266 DistributableImpl distributable = DistributableImpl.newInstance(); 267 distributable.setValidating(validate); 268 distributable.setCurrentUNode(distributable); 269 distributable.setParentUNode(null); 270 XMLReader parser = null; 272 String parserClass = System.getProperty("org.xml.sax.driver", 273 "org.apache.xerces.parsers.SAXParser"); 274 try { 275 parser = XMLReaderFactory.createXMLReader(parserClass); 276 277 if (entityResolver != null) { 279 parser.setEntityResolver(entityResolver); 280 } 281 282 parser.setErrorHandler(distributable); 284 285 parser.setProperty("http://xml.org/sax/properties/lexical-handler", distributable); 287 288 parser.setContentHandler(distributable); 290 } catch (SAXException e) { 291 throw new IOException ("Could not load XML parser: " + 292 e.getMessage()); 293 } 294 295 InputSource inputSource = new InputSource (reader); 296 try { 297 parser.setFeature("http://xml.org/sax/features/validation", new Boolean (validate).booleanValue()); 298 parser.setFeature("http://xml.org/sax/features/namespaces", true); 299 parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); 300 parser.parse(inputSource); 301 } catch (SAXException e) { 302 throw new IOException ("Error parsing XML document: " + 303 e.getMessage()); 304 } 305 306 return distributable; 308 } 309 310 public Unmarshallable getParentUNode() { 311 return zeus_parentUNode; 312 } 313 314 public void setParentUNode(Unmarshallable parentUNode) { 315 this.zeus_parentUNode = parentUNode; 316 } 317 318 public Unmarshallable getCurrentUNode() { 319 return zeus_currentUNode; 320 } 321 322 public void setCurrentUNode(Unmarshallable currentUNode) { 323 this.zeus_currentUNode = currentUNode; 324 } 325 326 public void setValidating(boolean validate) { 327 this.validate = validate; 328 } 329 330 public void startDocument() throws SAXException { 331 } 333 334 public void setDocumentLocator(Locator locator) { 335 } 337 338 public void startPrefixMapping(String prefix, String uri) 339 throws SAXException { 340 namespaceMappings.put(prefix, uri); 341 } 342 343 public void startElement(String namespaceURI, String localName, 344 String qName, org.xml.sax.Attributes atts) 345 throws SAXException { 346 347 Unmarshallable current = getCurrentUNode(); 349 if (current != this) { 350 current.startElement(namespaceURI, localName, qName, atts); 351 return; 352 } 353 354 if ((localName.equals("distributable")) && (!zeus_thisNodeHandled)) { 356 for (int i=0, len=atts.getLength(); i<len; i++) { 358 String attName= atts.getLocalName(i); 359 String attValue = atts.getValue(i); 360 if (attName.equals("id")) { 361 setId(attValue); 362 } 363 } 364 zeus_thisNodeHandled = true; 365 return; 366 } else { 367 } 369 } 370 371 public void endElement(String namespaceURI, String localName, 372 String qName) 373 throws SAXException { 374 375 Unmarshallable current = getCurrentUNode(); 376 if (current != this) { 377 current.endElement(namespaceURI, localName, qName); 378 return; 379 } 380 381 Unmarshallable parent = getCurrentUNode().getParentUNode(); 382 if (parent != null) { 383 parent.setCurrentUNode(parent); 384 } 385 } 386 387 public void characters(char[] ch, int start, int len) 388 throws SAXException { 389 390 Unmarshallable current = getCurrentUNode(); 392 if (current != this) { 393 current.characters(ch, start, len); 394 return; 395 } 396 397 String text = new String (ch, start, len); 398 } 399 400 public void comment(char ch[], int start, int len) throws SAXException { 401 } 403 404 public void warning(SAXParseException e) throws SAXException { 405 if (errorHandler != null) { 406 errorHandler.warning(e); 407 } 408 } 409 410 public void error(SAXParseException e) throws SAXException { 411 if ((validate) && (!hasDTD)) { 412 throw new SAXException ("Validation is turned on, but no DTD has been specified in the input XML document. Please supply a DTD through a DOCTYPE reference."); 413 } 414 if (errorHandler != null) { 415 errorHandler.error(e); 416 } 417 } 418 419 public void fatalError(SAXParseException e) throws SAXException { 420 if ((validate) && (!hasDTD)) { 421 throw new SAXException ("Validation is turned on, but no DTD has been specified in the input XML document. Please supply a DTD through a DOCTYPE reference."); 422 } 423 if (errorHandler != null) { 424 errorHandler.fatalError(e); 425 } 426 } 427 428 public void startDTD(String name, String publicID, String systemID) 429 throws SAXException { 430 431 if ((name == null) || (name.equals(""))) { 432 docTypeString = ""; 433 return; 434 } 435 436 hasDTD = true; 437 StringBuffer docTypeSB = new StringBuffer (); 438 boolean hasPublic = false; 439 440 docTypeSB.append("<!DOCTYPE ") 441 .append(name); 442 443 if ((publicID != null) && (!publicID.equals(""))) { 444 docTypeSB.append(" PUBLIC \"") 445 .append(publicID) 446 .append("\""); 447 hasPublic = true; 448 } 449 450 if ((systemID != null) && (!systemID.equals(""))) { 451 if (!hasPublic) { 452 docTypeSB.append(" SYSTEM"); 453 } 454 docTypeSB.append(" \"") 455 .append(systemID) 456 .append("\""); 457 458 } 459 460 docTypeSB.append(">"); 461 462 docTypeString = docTypeSB.toString(); 463 } 464 465 public void endDTD() throws SAXException { 466 } 468 469 public void startEntity(String name) throws SAXException { 470 } 472 473 public void endEntity(String name) throws SAXException { 474 } 476 477 public void startCDATA() throws SAXException { 478 } 480 481 public void endCDATA() throws SAXException { 482 } 484 485 } 486 | Popular Tags |