blob: bfded9882d55af7de337390e712be4e10e6479cb [file] [log] [blame]
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());
}
}