1 /* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.xsom.impl.parser; 27 28 import com.sun.xml.internal.xsom.XSDeclaration; 29 import com.sun.xml.internal.xsom.XmlString; 30 import com.sun.xml.internal.xsom.XSSimpleType; 31 import com.sun.xml.internal.xsom.impl.ForeignAttributesImpl; 32 import com.sun.xml.internal.xsom.impl.SchemaImpl; 33 import com.sun.xml.internal.xsom.impl.UName; 34 import com.sun.xml.internal.xsom.impl.Const; 35 import com.sun.xml.internal.xsom.impl.parser.state.NGCCRuntime; 36 import com.sun.xml.internal.xsom.impl.parser.state.Schema; 37 import com.sun.xml.internal.xsom.impl.util.Uri; 38 import com.sun.xml.internal.xsom.parser.AnnotationParser; 39 import com.sun.xml.internal.org.relaxng.datatype.ValidationContext; 40 import org.xml.sax.Attributes; 41 import org.xml.sax.EntityResolver; 42 import org.xml.sax.ErrorHandler; 43 import org.xml.sax.InputSource; 44 import org.xml.sax.Locator; 45 import org.xml.sax.SAXException; 46 import org.xml.sax.SAXParseException; 47 import org.xml.sax.helpers.LocatorImpl; 48 49 import java.io.IOException; 50 import java.net.URI; 51 import java.text.MessageFormat; 52 import java.util.Stack; 53 54 /** 55 * NGCCRuntime extended with various utility methods for 56 * parsing XML Schema. 57 * 58 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 59 */ 60 public class NGCCRuntimeEx extends NGCCRuntime implements PatcherManager { 61 62 /** coordinator. */ 63 public final ParserContext parser; 64 65 /** The schema currently being parsed. */ 66 public SchemaImpl currentSchema; 67 68 /** The @finalDefault value of the current schema. */ 69 public int finalDefault = 0; 70 /** The @blockDefault value of the current schema. */ 71 public int blockDefault = 0; 72 133 if(c==null || ignorableDuplicateComponent(c)) return; 134 135 reportError( Messages.format(Messages.ERR_DOUBLE_DEFINITION,c.getName()) ); 136 reportError( Messages.format(Messages.ERR_DOUBLE_DEFINITION_ORIGINAL), c.getLocator() ); 137 } 138 139 public static boolean ignorableDuplicateComponent(XSDeclaration c) { 140 if(c.getTargetNamespace().equals(Const.schemaNamespace)) { 141 if(c instanceof XSSimpleType) 142 // hide artificial "double definitions" on simple types 143 return true; 144 if(c.isGlobal() && c.getName().equals("anyType")) 145 return true; // ditto for anyType 146 } 147 return false; 148 } 149 150 151 152 /* registers a patcher that will run after all the parsing has finished. */ 153 public void addPatcher( Patch patcher ) { 154 parser.patcherManager.addPatcher(patcher); 155 } 156 public void addErrorChecker( Patch patcher ) { 157 parser.patcherManager.addErrorChecker(patcher); 158 } 159 public void reportError( String msg, Locator loc ) throws SAXException { 160 parser.patcherManager.reportError(msg,loc); 161 } 162 public void reportError( String msg ) throws SAXException { 163 reportError(msg,getLocator()); 164 } 165 166 167 /** 168 * Resolves relative URI found in the document. 169 * 170 * @param namespaceURI 171 * passed to the entity resolver. 172 * @param relativeUri 173 * value of the schemaLocation attribute. Can be null. 174 * 175 * @return 176 * non-null if {@link EntityResolver} returned an {@link InputSource}, 177 * or if the relativeUri parameter seems to be pointing to something. 178 * Otherwise it returns null, in which case import/include should be abandoned. 179 */ 180 private InputSource resolveRelativeURL( String namespaceURI, String relativeUri ) throws SAXException { 181 try { 182 String baseUri = getLocator().getSystemId(); 183 if(baseUri==null) 184 // if the base URI is not available, the document system ID is 185 // better than nothing. 186 baseUri=documentSystemId; 187 188 EntityResolver er = parser.getEntityResolver(); 189 String systemId = null; 190 191 if (relativeUri!=null) 192 systemId = Uri.resolve(baseUri,relativeUri); 193 194 if (er!=null) { 195 InputSource is = er.resolveEntity(namespaceURI,systemId); 196 if (is == null) { 197 try { 198 String normalizedSystemId = URI.create(systemId).normalize().toASCIIString(); 199 is = er.resolveEntity(namespaceURI,normalizedSystemId); 200 } catch (Exception e) { 201 // just ignore, this is a second try, return the fallback if this breaks 202 } 203 } 204 if (is != null) { 205 return is; 206 } 207 } 208 209 if (systemId!=null) 210 return new InputSource(systemId); 211 else 212 return null; 213 } catch (IOException e) { 214 SAXParseException se = new SAXParseException(e.getMessage(),getLocator(),e); 215 parser.errorHandler.error(se); 216 return null; 217 } 218 } 219 220 /** Includes the specified schema. */ 221 public void includeSchema( String schemaLocation ) throws SAXException { 222 NGCCRuntimeEx runtime = new NGCCRuntimeEx(parser,chameleonMode,this); 223 runtime.currentSchema = this.currentSchema; 224 runtime.blockDefault = this.blockDefault; 225 runtime.finalDefault = this.finalDefault; 226 227 if( schemaLocation==null ) { 228 SAXParseException e = new SAXParseException( 229 Messages.format( Messages.ERR_MISSING_SCHEMALOCATION ), getLocator() ); 230 parser.errorHandler.fatalError(e); 231 throw e; 232 } 233 234 runtime.parseEntity( resolveRelativeURL(null,schemaLocation), 235 true, currentSchema.getTargetNamespace(), getLocator() ); 236 } 237 238 /** Imports the specified schema. */ 239 public void importSchema( String ns, String schemaLocation ) throws SAXException { 240 NGCCRuntimeEx newRuntime = new NGCCRuntimeEx(parser,false,this); 241 InputSource source = resolveRelativeURL(ns,schemaLocation); 242 if(source!=null) 243 newRuntime.parseEntity( source, false, ns, getLocator() ); 244 // if source == null, 245 // we can't locate this document. Let's just hope that 246 // we already have the schema components for this schema 247 // or we will receive them in the future. 248 } 249 250 /** 251 * Called when a new document is being parsed and checks 252 * if the document has already been parsed before. 253 * 254 * <p> 255 * Used to avoid recursive inclusion. Note that the same 256 * document will be parsed multiple times if they are for different 257 * target namespaces. 258 * 300 if(existing==null) { 301 parser.parsedDocuments.put(document,document); 302 } else { 303 document = existing; 304 } 305 306 assert document !=null; 307 308 if(referer!=null) { 309 assert referer.document !=null : "referer "+referer.documentSystemId+" has docIdentity==null"; 310 referer.document.references.add(this.document); 311 this.document.referers.add(referer.document); 312 } 313 314 return existing!=null; 315 } 316 317 /** 318 * Parses the specified entity. 319 * 320 * @param importLocation 321 * The source location of the import/include statement. 322 * Used for reporting errors. 323 */ 324 public void parseEntity( InputSource source, boolean includeMode, String expectedNamespace, Locator importLocation ) 325 throws SAXException { 326 327 documentSystemId = source.getSystemId(); 328 try { 329 Schema s = new Schema(this,includeMode,expectedNamespace); 330 setRootHandler(s); 331 try { 332 parser.parser.parse(source,this, getErrorHandler(), parser.getEntityResolver()); 333 } catch( IOException fnfe ) { 334 SAXParseException se = new SAXParseException(fnfe.toString(), importLocation, fnfe); 335 parser.errorHandler.warning(se); 336 } 337 } catch( SAXException e ) { 338 parser.setErrorFlag(); 339 throw e; 340 } 341 } 342 343 /** 344 * Creates a new instance of annotation parser. 345 */ 346 public AnnotationParser createAnnotationParser() { 347 if(parser.getAnnotationParserFactory()==null) 348 return DefaultAnnotationParser.theInstance; 349 else 350 return parser.getAnnotationParserFactory().create(); 351 } 352 353 /** 354 * Gets the element name that contains the annotation element. 355 * This method works correctly only when called by the annotation handler. 356 */ 357 public String getAnnotationContextElementName() { 358 return elementNames.get( elementNames.size()-2 ); 359 } 360 361 /** Creates a copy of the current locator object. */ 362 public Locator copyLocator() { 363 return new LocatorImpl(getLocator()); 364 } 365 366 public ErrorHandler getErrorHandler() { 367 return parser.errorHandler; 368 } 369 370 @Override 371 public void onEnterElementConsumed(String uri, String localName, String qname, Attributes atts) 372 throws SAXException { 373 super.onEnterElementConsumed(uri, localName, qname, atts); 374 elementNames.push(localName); 375 } 376 377 @Override 378 public void onLeaveElementConsumed(String uri, String localName, String qname) throws SAXException { 379 super.onLeaveElementConsumed(uri, localName, qname); 380 elementNames.pop(); 381 } 382 383 384 385 // 386 // 387 // ValidationContext implementation 388 // 389 // 390 // this object lives longer than the parser itself, 391 // so it's important for this object not to have any reference 392 // to the parser. 393 private static class Context implements ValidationContext { 394 Context( String _prefix, String _uri, Context _context ) { 395 this.previous = _context; 396 this.prefix = _prefix; 397 this.uri = _uri; 398 } 399 400 public String resolveNamespacePrefix(String p) { 401 if(p.equals(prefix)) return uri; 402 if(previous==null) return null; 403 else return previous.resolveNamespacePrefix(p); 404 } 405 406 private final String prefix; 407 private final String uri; 408 private final Context previous; 409 410 // XSDLib don't use those methods, so we cut a corner here. 411 public String getBaseUri() { return null; } 412 public boolean isNotation(String arg0) { return false; } 413 public boolean isUnparsedEntity(String arg0) { return false; } 414 } 415 416 private Context currentContext=null; 417 418 /** Returns an immutable snapshot of the current context. */ 419 public ValidationContext createValidationContext() { 420 return currentContext; 421 } 422 423 public XmlString createXmlString(String value) { 424 if(value==null) return null; 425 else return new XmlString(value,createValidationContext()); 426 } 427 428 @Override 429 public void startPrefixMapping( String prefix, String uri ) throws SAXException { 430 super.startPrefixMapping(prefix,uri); 431 currentContext = new Context(prefix,uri,currentContext); 432 } 433 @Override 434 public void endPrefixMapping( String prefix ) throws SAXException { 435 super.endPrefixMapping(prefix); 436 currentContext = currentContext.previous; 437 } 438 439 // 440 // 441 // Utility functions 442 // 443 // 444 445 /** 446 * Parses UName under the given context. 447 * @param qname Attribute name. 448 * @return New {@link UName} instance based on attribute name. 449 */ 450 public UName parseUName(final String qname ) throws SAXException { 451 int idx = qname.indexOf(':'); 452 if(idx<0) { 453 String uri = resolveNamespacePrefix(""); 454 455 // chamelon behavior. ugly... 456 if( uri.equals("") && chameleonMode ) 457 uri = currentSchema.getTargetNamespace(); 458 459 // this is guaranteed to resolve 460 return new UName(uri,qname,qname); 461 } else { 462 String prefix = qname.substring(0,idx); 463 String uri = currentContext.resolveNamespacePrefix(prefix); 464 if(uri==null) { 465 // prefix failed to resolve. 466 reportError(Messages.format( 467 Messages.ERR_UNDEFINED_PREFIX,prefix)); 468 uri="undefined"; // replace with a dummy | 1 /* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.xsom.impl.parser; 27 28 import com.sun.xml.internal.xsom.XSDeclaration; 29 import com.sun.xml.internal.xsom.XmlString; 30 import com.sun.xml.internal.xsom.XSSimpleType; 31 import com.sun.xml.internal.xsom.impl.ForeignAttributesImpl; 32 import com.sun.xml.internal.xsom.impl.SchemaImpl; 33 import com.sun.xml.internal.xsom.impl.UName; 34 import com.sun.xml.internal.xsom.impl.Const; 35 import com.sun.xml.internal.xsom.impl.parser.state.NGCCRuntime; 36 import com.sun.xml.internal.xsom.impl.parser.state.Schema; 37 import com.sun.xml.internal.xsom.parser.AnnotationParser; 38 import com.sun.xml.internal.org.relaxng.datatype.ValidationContext; 39 import org.xml.sax.Attributes; 40 import org.xml.sax.EntityResolver; 41 import org.xml.sax.ErrorHandler; 42 import org.xml.sax.InputSource; 43 import org.xml.sax.Locator; 44 import org.xml.sax.SAXException; 45 import org.xml.sax.SAXParseException; 46 import org.xml.sax.helpers.LocatorImpl; 47 48 import java.io.IOException; 49 import java.net.URI; 50 import java.net.URL; 51 import java.text.MessageFormat; 52 import java.util.Stack; 53 import java.util.regex.Pattern; 54 55 /** 56 * NGCCRuntime extended with various utility methods for 57 * parsing XML Schema. 58 * 59 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 60 */ 61 public class NGCCRuntimeEx extends NGCCRuntime implements PatcherManager { 62 63 /** coordinator. */ 64 public final ParserContext parser; 65 66 /** The schema currently being parsed. */ 67 public SchemaImpl currentSchema; 68 69 /** The @finalDefault value of the current schema. */ 70 public int finalDefault = 0; 71 /** The @blockDefault value of the current schema. */ 72 public int blockDefault = 0; 73 134 if(c==null || ignorableDuplicateComponent(c)) return; 135 136 reportError( Messages.format(Messages.ERR_DOUBLE_DEFINITION,c.getName()) ); 137 reportError( Messages.format(Messages.ERR_DOUBLE_DEFINITION_ORIGINAL), c.getLocator() ); 138 } 139 140 public static boolean ignorableDuplicateComponent(XSDeclaration c) { 141 if(c.getTargetNamespace().equals(Const.schemaNamespace)) { 142 if(c instanceof XSSimpleType) 143 // hide artificial "double definitions" on simple types 144 return true; 145 if(c.isGlobal() && c.getName().equals("anyType")) 146 return true; // ditto for anyType 147 } 148 return false; 149 } 150 151 152 153 /* registers a patcher that will run after all the parsing has finished. */ 154 @Override 155 public void addPatcher( Patch patcher ) { 156 parser.patcherManager.addPatcher(patcher); 157 } 158 @Override 159 public void addErrorChecker( Patch patcher ) { 160 parser.patcherManager.addErrorChecker(patcher); 161 } 162 @Override 163 public void reportError( String msg, Locator loc ) throws SAXException { 164 parser.patcherManager.reportError(msg,loc); 165 } 166 public void reportError( String msg ) throws SAXException { 167 reportError(msg,getLocator()); 168 } 169 170 171 /** 172 * Resolves relative URI found in the document. 173 * 174 * @param namespaceURI 175 * passed to the entity resolver. 176 * @param relativeUri 177 * value of the schemaLocation attribute. Can be null. 178 * 179 * @return 180 * non-null if {@link EntityResolver} returned an {@link InputSource}, 181 * or if the relativeUri parameter seems to be pointing to something. 182 * Otherwise it returns null, in which case import/include should be abandoned. 183 */ 184 private InputSource resolveRelativeURL( String namespaceURI, String relativeUri ) throws SAXException { 185 try { 186 String baseUri = getLocator().getSystemId(); 187 if(baseUri==null) 188 // if the base URI is not available, the document system ID is 189 // better than nothing. 190 baseUri=documentSystemId; 191 192 EntityResolver er = parser.getEntityResolver(); 193 String systemId = null; 194 195 if (relativeUri!=null) { 196 if (isAbsolute(relativeUri)) { 197 systemId = relativeUri; 198 } 199 if (baseUri == null || !isAbsolute(baseUri)) { 200 throw new IOException("Unable to resolve relative URI " + relativeUri + " because base URI is not absolute: " + baseUri); 201 } 202 systemId = new URL(new URL(baseUri), relativeUri).toString(); 203 } 204 205 if (er!=null) { 206 InputSource is = er.resolveEntity(namespaceURI,systemId); 207 if (is == null) { 208 try { 209 String normalizedSystemId = URI.create(systemId).normalize().toASCIIString(); 210 is = er.resolveEntity(namespaceURI,normalizedSystemId); 211 } catch (Exception e) { 212 // just ignore, this is a second try, return the fallback if this breaks 213 } 214 } 215 if (is != null) { 216 return is; 217 } 218 } 219 220 if (systemId!=null) 221 return new InputSource(systemId); 222 else 223 return null; 224 } catch (IOException e) { 225 SAXParseException se = new SAXParseException(e.getMessage(),getLocator(),e); 226 parser.errorHandler.error(se); 227 return null; 228 } 229 } 230 231 private static final Pattern P = Pattern.compile(".*[/#?].*"); 232 233 private static boolean isAbsolute(String uri) { 234 int i = uri.indexOf(':'); 235 if (i < 0) { 236 return false; 237 } 238 return !P.matcher(uri.substring(0, i)).matches(); 239 } 240 241 /** 242 * Includes the specified schema. 243 * @param schemaLocation 244 * @throws org.xml.sax.SAXException */ 245 public void includeSchema( String schemaLocation ) throws SAXException { 246 NGCCRuntimeEx runtime = new NGCCRuntimeEx(parser,chameleonMode,this); 247 runtime.currentSchema = this.currentSchema; 248 runtime.blockDefault = this.blockDefault; 249 runtime.finalDefault = this.finalDefault; 250 251 if( schemaLocation==null ) { 252 SAXParseException e = new SAXParseException( 253 Messages.format( Messages.ERR_MISSING_SCHEMALOCATION ), getLocator() ); 254 parser.errorHandler.fatalError(e); 255 throw e; 256 } 257 258 runtime.parseEntity( resolveRelativeURL(null,schemaLocation), 259 true, currentSchema.getTargetNamespace(), getLocator() ); 260 } 261 262 /** 263 * Imports the specified schema. 264 * @param ns 265 * @param schemaLocation 266 * @throws org.xml.sax.SAXException */ 267 public void importSchema( String ns, String schemaLocation ) throws SAXException { 268 NGCCRuntimeEx newRuntime = new NGCCRuntimeEx(parser,false,this); 269 InputSource source = resolveRelativeURL(ns,schemaLocation); 270 if(source!=null) 271 newRuntime.parseEntity( source, false, ns, getLocator() ); 272 // if source == null, 273 // we can't locate this document. Let's just hope that 274 // we already have the schema components for this schema 275 // or we will receive them in the future. 276 } 277 278 /** 279 * Called when a new document is being parsed and checks 280 * if the document has already been parsed before. 281 * 282 * <p> 283 * Used to avoid recursive inclusion. Note that the same 284 * document will be parsed multiple times if they are for different 285 * target namespaces. 286 * 328 if(existing==null) { 329 parser.parsedDocuments.put(document,document); 330 } else { 331 document = existing; 332 } 333 334 assert document !=null; 335 336 if(referer!=null) { 337 assert referer.document !=null : "referer "+referer.documentSystemId+" has docIdentity==null"; 338 referer.document.references.add(this.document); 339 this.document.referers.add(referer.document); 340 } 341 342 return existing!=null; 343 } 344 345 /** 346 * Parses the specified entity. 347 * 348 * @param source 349 * @param importLocation 350 * The source location of the import/include statement. 351 * Used for reporting errors. 352 * @param includeMode 353 * @param expectedNamespace 354 * @throws org.xml.sax.SAXException 355 */ 356 public void parseEntity( InputSource source, boolean includeMode, String expectedNamespace, Locator importLocation ) 357 throws SAXException { 358 359 documentSystemId = source.getSystemId(); 360 try { 361 Schema s = new Schema(this,includeMode,expectedNamespace); 362 setRootHandler(s); 363 try { 364 parser.parser.parse(source,this, getErrorHandler(), parser.getEntityResolver()); 365 } catch( IOException fnfe ) { 366 SAXParseException se = new SAXParseException(fnfe.toString(), importLocation, fnfe); 367 parser.errorHandler.warning(se); 368 } 369 } catch( SAXException e ) { 370 parser.setErrorFlag(); 371 throw e; 372 } 373 } 374 375 /** 376 * Creates a new instance of annotation parser. 377 * @return 378 */ 379 public AnnotationParser createAnnotationParser() { 380 if(parser.getAnnotationParserFactory()==null) 381 return DefaultAnnotationParser.theInstance; 382 else 383 return parser.getAnnotationParserFactory().create(); 384 } 385 386 /** 387 * Gets the element name that contains the annotation element.This method works correctly only when called by the annotation handler. 388 * @return 389 */ 390 public String getAnnotationContextElementName() { 391 return elementNames.get( elementNames.size()-2 ); 392 } 393 394 /** Creates a copy of the current locator object. 395 * @return */ 396 public Locator copyLocator() { 397 return new LocatorImpl(getLocator()); 398 } 399 400 public ErrorHandler getErrorHandler() { 401 return parser.errorHandler; 402 } 403 404 @Override 405 public void onEnterElementConsumed(String uri, String localName, String qname, Attributes atts) 406 throws SAXException { 407 super.onEnterElementConsumed(uri, localName, qname, atts); 408 elementNames.push(localName); 409 } 410 411 @Override 412 public void onLeaveElementConsumed(String uri, String localName, String qname) throws SAXException { 413 super.onLeaveElementConsumed(uri, localName, qname); 414 elementNames.pop(); 415 } 416 417 418 419 // 420 // 421 // ValidationContext implementation 422 // 423 // 424 // this object lives longer than the parser itself, 425 // so it's important for this object not to have any reference 426 // to the parser. 427 private static class Context implements ValidationContext { 428 Context( String _prefix, String _uri, Context _context ) { 429 this.previous = _context; 430 this.prefix = _prefix; 431 this.uri = _uri; 432 } 433 434 @Override 435 public String resolveNamespacePrefix(String p) { 436 if(p.equals(prefix)) return uri; 437 if(previous==null) return null; 438 else return previous.resolveNamespacePrefix(p); 439 } 440 441 private final String prefix; 442 private final String uri; 443 private final Context previous; 444 445 // XSDLib don't use those methods, so we cut a corner here. 446 @Override 447 public String getBaseUri() { return null; } 448 @Override 449 public boolean isNotation(String arg0) { return false; } 450 @Override 451 public boolean isUnparsedEntity(String arg0) { return false; } 452 } 453 454 private Context currentContext=null; 455 456 /** Returns an immutable snapshot of the current context. 457 * @return */ 458 public ValidationContext createValidationContext() { 459 return currentContext; 460 } 461 462 public XmlString createXmlString(String value) { 463 if(value==null) return null; 464 else return new XmlString(value,createValidationContext()); 465 } 466 467 @Override 468 public void startPrefixMapping( String prefix, String uri ) throws SAXException { 469 super.startPrefixMapping(prefix,uri); 470 currentContext = new Context(prefix,uri,currentContext); 471 } 472 @Override 473 public void endPrefixMapping( String prefix ) throws SAXException { 474 super.endPrefixMapping(prefix); 475 currentContext = currentContext.previous; 476 } 477 478 // 479 // 480 // Utility functions 481 // 482 // 483 484 /** 485 * Parses UName under the given context. 486 * @param qname Attribute name. 487 * @return New {@link UName} instance based on attribute name. 488 * @throws org.xml.sax.SAXException 489 */ 490 public UName parseUName(final String qname ) throws SAXException { 491 int idx = qname.indexOf(':'); 492 if(idx<0) { 493 String uri = resolveNamespacePrefix(""); 494 495 // chamelon behavior. ugly... 496 if( uri.equals("") && chameleonMode ) 497 uri = currentSchema.getTargetNamespace(); 498 499 // this is guaranteed to resolve 500 return new UName(uri,qname,qname); 501 } else { 502 String prefix = qname.substring(0,idx); 503 String uri = currentContext.resolveNamespacePrefix(prefix); 504 if(uri==null) { 505 // prefix failed to resolve. 506 reportError(Messages.format( 507 Messages.ERR_UNDEFINED_PREFIX,prefix)); 508 uri="undefined"; // replace with a dummy |