| package org.apache.xml.dtm.ref.xni2dtm; |
| |
| import org.w3c.dom.Node; |
| import org.apache.xml.dtm.DTM; |
| import org.apache.xml.dtm.DTMManager; |
| import org.apache.xml.dtm.ref.DTMDefaultBase; |
| import org.apache.xml.dtm.ref.DTMNodeProxy; |
| import org.apache.xml.dtm.ref.xni2dtm.XNI2DTM; |
| import org.apache.xml.dtm.ref.xni2dtm.DTM2XNI; |
| import org.apache.xpath.XPathContext; |
| |
| /** Temporary extension function, prototyping proposed XPath2 FuncValidate. |
| * |
| * This may be moved back to XSLT/XQuery, or may be folded all the way down |
| * as an operation implied by low-level expression syntax, depending on what |
| * happens in the Working Group. |
| * |
| * %REVIEW% Current code validates only a single root element. If we want more, |
| * we can do it but it'll take a bit more coding. |
| * */ |
| public class FuncValidate { |
| private static final boolean JJK_DISABLE_VALIDATOR=false; // debugging hook |
| private static final boolean JJK_DUMMY_CODE=true; // debugging hook |
| |
| |
| public static Node eval(org.apache.xalan.extensions.ExpressionContext context, |
| Node root) |
| { |
| return eval(context,root,null); |
| } |
| public static Node eval(org.apache.xalan.extensions.ExpressionContext expressionContext, |
| Node root, String contextPath) |
| { |
| // This happens to work in current code. It isn't really |
| // documented. Future versions expect to expose it more elegantly, |
| // according to Don Leslie. But since this extension is just |
| // temporary, let's use the cheat... We know it's going to be a |
| // particular inner class, which has an accessor to retrieve its |
| // associated XPathContext, so we reach in and ask it to reach back. |
| XPathContext xctxt = ((XPathContext.XPathExpressionContext)expressionContext).getXPathContext(); |
| |
| int sourceHandle=xctxt.getDTMHandleFromNode(root); |
| DTM sourceDTM=xctxt.getDTM(sourceHandle); |
| |
| DTM2XNI d2x=new DTM2XNI(sourceDTM,sourceHandle); |
| |
| // %REVIEW% Still need to do something with contextPath. |
| // d2x is set up to synthesize a wrapper and then discard it again -- |
| // BUT this fails when one of the synthesized elements has attr requirements, |
| // as Xerces apparently optimizes by not validating kids if the start-tag |
| // isn't valid. |
| // |
| // A better answer would be to set the validator's context; |
| // Xerces agrees that this is a desirable feature but may not have |
| // implemented it yet. |
| if(contextPath!=null) |
| { |
| java.util.Vector d2xContext=new java.util.Vector(); |
| // xctxt not available to extensions? |
| org.apache.xml.utils.PrefixResolver pfxresolver=xctxt.getNamespaceContext(); |
| |
| java.util.StringTokenizer e=new java.util.StringTokenizer(contextPath,"/"); |
| while(e.hasMoreElements()) |
| { |
| String name=(String)e.nextElement(); |
| org.apache.xml.utils.QName qn=new org.apache.xml.utils.QName(name,pfxresolver); |
| d2xContext.addElement(qn); |
| } |
| d2x.setContext(d2xContext); |
| } |
| |
| // VALIDATION GOES HERE! |
| // Sandy Gao recommends "create a customized parser configuration, |
| // which contains an XNI event source, a validator, and (optionally) |
| // a document handler." See "pipelines" in the XNI docs. |
| // I don't really grok that yet, so this is a SWAG based on what |
| // Elena Litani did for the DOM revalidator. |
| // |
| // If we need to suppress explicit xsi:*schemaLocation directives, recommended |
| // kluge is to install a entity-resolver into the pipe which delivered |
| // a schema with appropriate targetNamespae and no details (or just empty???) |
| // |
| // If we need to suppress explicit xsi:type directives -- Xerces developers |
| // agree with me that this is Inherently Stupid. Solution would be to pass |
| // those through a secondary channel, eg by turning them into custom |
| // annotations until they get back to XNI. |
| XNISource xsrc; |
| if(JJK_DISABLE_VALIDATOR) |
| xsrc=new XNISource(d2x,null); // Test: Just flow thru |
| else |
| { |
| // ISSUE: Do we need to explicitly normalize namespaces? |
| |
| /* Adapted from Xerces DOMRevalidator. |
| Probably shouldn't be using this class, but |
| I haven't yet gotten the Xerces team to give me |
| a real stand-alone example I could model this on. |
| |
| I'm also REALLY not convinced this is a typical XNI setup; |
| I'm surprised I have to muck directly with the validator |
| rather than setting up a configuration that encapsulates |
| the dataflow more completely. (On the other hand, I'm also |
| surpised that Configuration doesn't seem to implement |
| DocumentSource. |
| */ |
| DOMValidationConfigurationSwipedFromXerces xnipipe |
| =new DOMValidationConfigurationSwipedFromXerces(null); |
| xnipipe.setFeature(DOMValidationConfigurationSwipedFromXerces.VALIDATION,true); |
| xnipipe.setFeature(DOMValidationConfigurationSwipedFromXerces.SCHEMA,true); |
| org.apache.xerces.impl.xs.XMLSchemaValidator validator |
| =new org.apache.xerces.impl.xs.XMLSchemaValidator(); |
| xnipipe.addComponent(validator); // so config's reset() hits it |
| |
| if(JJK_DUMMY_CODE) |
| { |
| /* %REVIEW% Code in this section is preliminary/bogus, |
| for debugging only */ |
| |
| /* %ISSUE% 1) Is there such a thing as a base URI for this fragment? |
| %BUG% It is very unclear that this fragment has a real base URI. |
| Also, note that this call fails for RTFDTMs. |
| |
| (We may in fact need to set this otherwise to prevent |
| xsi:schemaLocation from succeeding, unless we can tell |
| Xerces not to honor that directive.. or filter it out |
| in DTM2XNI, ugh. For now leave this unset to expose |
| failure to reference the explicitly loaded GrammarPool.) |
| */ |
| //validator.setBaseURI(sourceDTM.getDocumentBaseURI()); |
| |
| /* %ISSUE% 2) Do we need to track mid-stream changes by issuing |
| entity/locator information into the stream? |
| %BUG% It is very unclear that this fragment has a real base URI. |
| Also, we don't actually record that data node-by-node unless |
| tooling support is turned on... and even then I'm not sure |
| this is retained after a layer or two of RTFs. |
| */ |
| // No. |
| |
| /* %ISSUE% 3) XPath2 says schema location comes from the XPath context, |
| *not* from the document. Need to assert this via the |
| schemaLocation property, or preparse into a Grammar Pool |
| and use that. (I expect the latter since other parts of |
| XPath2/XQuery/XSLT2 also want to muck with schemas.) |
| |
| %TODO%: Need to add that to the XPathContext and |
| Xalan startup? |
| */ |
| // Experimental, force it in manually just to see what happens |
| xnipipe.setProperty(xnipipe.GRAMMAR_POOL, |
| xctxt.getInScopeSchemaDefinitions().getGrammarPool()); |
| |
| /* %ISSUE% 5) NOTE that we're making no effort to retain existing |
| type info (per latest XPath data I've seen). If we were, |
| we get into ugly issues w/r/t having to retain type on |
| Literal Result Elements in the stylesheet, plus questions |
| about what (if anything) happens when an LRE has |
| an xsi:type. The XQUERY team is still flailing on this topic. |
| */ |
| } |
| |
| |
| d2x.setDocumentHandler(validator); |
| |
| // Wrap up the pipeline for our use. |
| // There ought to be a way to avoid passing all these parts... |
| xsrc=new XNISource(d2x,xnipipe,validator,null); |
| } |
| |
| // %REVIEW% %BUG% |
| // I don't think we can make this incremental, attractive |
| // as that thought might be -- the source DTM might be an RTF and |
| // might Go Away. We probably _should_ make it an RTF DTM, but those |
| // currently aren't supported for XNI. |
| DTM newDTM=xctxt.getDTM(xsrc, |
| true, // unique |
| null, // whitespace filter |
| false, // incremental -- not supported at this writing |
| false // doIndexing -- open to debate |
| ); |
| |
| return newDTM.getNode(newDTM.getDocument()); |
| } |
| } |
| |