Source for gnu.xml.libxmlj.dom.GnomeDocumentBuilder

   1: /* GnomeDocumentBuilder.java -
   2:    Copyright (C) 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.xml.libxmlj.dom;
  39: 
  40: import java.io.InputStream;
  41: import java.io.IOException;
  42: import java.net.URL;
  43: import javax.xml.parsers.DocumentBuilder;
  44: 
  45: import org.w3c.dom.Document;
  46: import org.w3c.dom.DocumentType;
  47: import org.w3c.dom.DOMImplementation;
  48: import org.xml.sax.EntityResolver;
  49: import org.xml.sax.ErrorHandler;
  50: import org.xml.sax.InputSource;
  51: import org.xml.sax.Locator;
  52: import org.xml.sax.SAXException;
  53: import org.xml.sax.SAXParseException;
  54: 
  55: import gnu.xml.libxmlj.util.NamedInputStream;
  56: import gnu.xml.libxmlj.util.StandaloneDocumentType;
  57: import gnu.xml.libxmlj.util.StandaloneLocator;
  58: import gnu.xml.libxmlj.util.XMLJ;
  59: 
  60: /**
  61:  * A JAXP DOM implementation that uses Gnome libxml2 as the underlying
  62:  * parser and node representation.
  63:  *
  64:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  65:  */
  66: public class GnomeDocumentBuilder
  67:   extends DocumentBuilder
  68:   implements DOMImplementation
  69: {
  70: 
  71:   static
  72:   {
  73:     XMLJ.init();
  74:   }
  75: 
  76:   // -- DocumentBuilder --
  77: 
  78:   private boolean validate;
  79:   private boolean coalesce;
  80:   private boolean expandEntities;
  81:   private EntityResolver entityResolver;
  82:   private ErrorHandler errorHandler;
  83:   private boolean seenFatalError;
  84: 
  85:   /**
  86:    * Constructs a new validating document builder.
  87:    */
  88:   public GnomeDocumentBuilder()
  89:   {
  90:     this(true, false, false);
  91:   }
  92: 
  93:   /**
  94:    * Constructs a new document builder.
  95:    * @param validate whether to validate during parsing
  96:    * @param coalesce whether to merge CDATA as text nodes
  97:    * @param expandEntities whether to expand entity references
  98:    */
  99:   public GnomeDocumentBuilder(boolean validate,
 100:                               boolean coalesce,
 101:                               boolean expandEntities)
 102:   {
 103:     this.validate = validate;
 104:     this.coalesce = coalesce;
 105:     this.expandEntities = expandEntities;
 106:   }
 107: 
 108:   public DOMImplementation getDOMImplementation()
 109:   {
 110:     return this;
 111:   }
 112: 
 113:   public boolean isNamespaceAware()
 114:   {
 115:     return true;
 116:   }
 117: 
 118:   public boolean isValidating()
 119:   {
 120:     return validate;
 121:   }
 122: 
 123:   public Document newDocument()
 124:   {
 125:     return createDocument(null, null, null);
 126:   }
 127: 
 128:   public Document parse(InputSource input)
 129:     throws SAXException, IOException
 130:   {
 131:     NamedInputStream in = XMLJ.getInputStream(input);
 132:     byte[] detectBuffer = in.getDetectBuffer();
 133:     String publicId = input.getPublicId();
 134:     String systemId = input.getSystemId();
 135:     String base = XMLJ.getBaseURI(systemId);
 136:     // Handle zero-length document
 137:     if (detectBuffer == null)
 138:       {
 139:         throw new SAXParseException("No document element", publicId,
 140:                                     systemId, 0, 0);
 141:       }
 142:     seenFatalError = false;
 143:     return parseStream(in,
 144:                        detectBuffer,
 145:                        publicId,
 146:                        systemId,
 147:                        base,
 148:                        validate,
 149:                        coalesce,
 150:                        expandEntities,
 151:                        true, //entityResolver != null,
 152:                        errorHandler != null);
 153:   }
 154: 
 155:   private native Document parseStream(InputStream in,
 156:                                       byte[] detectBuffer,
 157:                                       String publicId,
 158:                                       String systemId,
 159:                                       String base,
 160:                                       boolean validate,
 161:                                       boolean coalesce,
 162:                                       boolean expandEntities,
 163:                                       boolean entityResolver,
 164:                                       boolean errorHandler);
 165: 
 166:   public void setEntityResolver(EntityResolver resolver)
 167:   {
 168:     entityResolver = resolver;
 169:   }
 170: 
 171:   public void setErrorHandler(ErrorHandler handler)
 172:   {
 173:     errorHandler = handler;
 174:   }
 175: 
 176:   // -- DOMImplementation --
 177: 
 178:   public boolean hasFeature(String name, String version)
 179:   {
 180:     if (name.length() == 0)
 181:       {
 182:         return false;
 183:       }
 184:     name = name.toLowerCase();
 185:     if (name.charAt(0) == '+')
 186:       {
 187:         name = name.substring(1);
 188:       }
 189: 
 190:     if ("xml".equals(name) || "core".equals(name))
 191:       {
 192:         return (version == null ||
 193:                 "".equals(version) ||
 194:                 "1.0".equals(version) ||
 195:                 "2.0".equals(version) ||
 196:                 "3.0".equals(version));
 197: 
 198:       }
 199:     else if ("ls".equals(name) || "ls-async".equals(name))
 200:       {
 201:         // TODO
 202:         /*
 203:         return (version == null ||
 204:                 "".equals(version) ||
 205:                 "3.0".equals(version));
 206:                 */
 207:         return false;
 208:       }
 209:     else if ("traversal".equals(name))
 210:       {
 211:         return (version == null ||
 212:                 "".equals(version) ||
 213:                 "2.0".equals(version));
 214:       }
 215:     else if ("xpath".equals(name))
 216:       {
 217:         return (version == null ||
 218:                 "".equals(version) ||
 219:                 "3.0".equals(version));
 220:       }
 221:     return false;
 222:   }
 223: 
 224:   // DOM Level 3
 225: 
 226:   public Object getFeature(String feature, String version)
 227:   {
 228:     if (hasFeature(feature, version))
 229:       {
 230:         return this;
 231:       }
 232:     return null;
 233:   }
 234: 
 235:   public native Document createDocument(String namespaceURI,
 236:                                         String qualifiedName,
 237:                                         DocumentType doctype);
 238: 
 239:   public DocumentType createDocumentType(String qualifiedName,
 240:                                          String publicId,
 241:                                          String systemId)
 242:   {
 243:     return new StandaloneDocumentType(qualifiedName, publicId, systemId);
 244:   }
 245: 
 246:   // Callback hooks from JNI
 247: 
 248:   private void setDocumentLocator(Object ctx, Object loc)
 249:   {
 250:     // ignore
 251:   }
 252: 
 253:   private InputStream resolveEntity(String publicId, String systemId,
 254:                                     String base)
 255:     throws SAXException, IOException
 256:   {
 257:     String url = XMLJ.getAbsoluteURI(base, systemId);
 258:     InputStream in = null;
 259:     if (entityResolver != null)
 260:       {
 261:         InputSource source = entityResolver.resolveEntity(publicId, url);
 262:         if (source != null)
 263:           {
 264:             in = XMLJ.getInputStream(source);
 265:           }
 266:       }
 267:     if (in == null)
 268:       {
 269:         in  = XMLJ.getInputStream(new URL(url));
 270:       }
 271:     return in;
 272:   }
 273: 
 274:   private void warning(String message,
 275:                        int lineNumber,
 276:                        int columnNumber,
 277:                        String publicId,
 278:                        String systemId)
 279:     throws SAXException
 280:   {
 281:     if (!seenFatalError && errorHandler != null)
 282:       {
 283:         Locator l = new StandaloneLocator(lineNumber,
 284:                                           columnNumber,
 285:                                           publicId,
 286:                                           systemId);
 287:         errorHandler.warning(new SAXParseException(message, l));
 288:       }
 289:   }
 290: 
 291:   private void error(String message,
 292:                      int lineNumber,
 293:                      int columnNumber,
 294:                      String publicId,
 295:                      String systemId)
 296:     throws SAXException
 297:   {
 298:     if (!seenFatalError && errorHandler != null)
 299:       {
 300:         Locator l = new StandaloneLocator(lineNumber,
 301:                                           columnNumber,
 302:                                           publicId,
 303:                                           systemId);
 304:         errorHandler.error(new SAXParseException(message, l));
 305:       }
 306:   }
 307: 
 308:   private void fatalError(String message,
 309:                           int lineNumber,
 310:                           int columnNumber,
 311:                           String publicId,
 312:                           String systemId)
 313:     throws SAXException
 314:   {
 315:     if (!seenFatalError && errorHandler != null)
 316:       {
 317:         seenFatalError = true;
 318:         Locator l = new StandaloneLocator(lineNumber,
 319:                                           columnNumber,
 320:                                           publicId,
 321:                                           systemId);
 322:         errorHandler.fatalError(new SAXParseException(message, l));
 323:       }
 324:   }
 325: 
 326: }