Hashtable<String,String> localBindings = new Hashtable<String,String> ();
// Compute the namespaces associated with this binding
if (nsbinding.getBinding() != null) {
QName binding = new QName(nsbinding.getBinding(), nsbinding.getNode());
RuntimeValue nsv = globals.get(binding);
if (nsv == null) {
throw new XProcException(var.getNode(), "No in-scope option or variable named: " + binding);
}
localBindings = nsv.getNamespaceBindings();
} else if (nsbinding.getXPath() != null) {
try {
XPathCompiler xcomp = runtime.getProcessor().newXPathCompiler();
xcomp.setBaseURI(step.getNode().getBaseURI());
for (QName varname : globals.keySet()) {
xcomp.declareVariable(varname);
}
// Make sure the namespace bindings for evaluating the XPath expr are correct
// FIXME: Surely there's a better way to do this?
Hashtable<String,String> lclnsBindings = new Hashtable<String, String>();
NodeInfo inode = nsbinding.getNode().getUnderlyingNode();
NamePool pool = inode.getNamePool();
InscopeNamespaceResolver inscopeNS = new InscopeNamespaceResolver(inode);
Iterator<?> pfxiter = inscopeNS.iteratePrefixes();
while (pfxiter.hasNext()) {
String nspfx = (String)pfxiter.next();
String nsuri = inscopeNS.getURIForPrefix(nspfx, "".equals(nspfx));
lclnsBindings.put(nspfx, nsuri);
}
for (String prefix : lclnsBindings.keySet()) {
xcomp.declareNamespace(prefix, lclnsBindings.get(prefix));
}
XPathExecutable xexec = xcomp.compile(nsbinding.getXPath());
XPathSelector selector = xexec.load();
for (QName varname : globals.keySet()) {
XdmAtomicValue avalue = new XdmAtomicValue(globals.get(varname).getString());
selector.setVariable(varname,avalue);
}
if (doc != null) {
selector.setContextItem(doc);
}
XdmNode element = null;
Iterator<XdmItem> values = selector.iterator();
while (values.hasNext()) {
XdmItem item = values.next();
if (element != null || item.isAtomicValue()) {
throw XProcException.dynamicError(9);
}
element = (XdmNode) item;
if (element.getNodeKind() != XdmNodeKind.ELEMENT) {
throw XProcException.dynamicError(9);
}
}
if (element == null) {
throw XProcException.dynamicError(9);
}
XdmSequenceIterator nsIter = element.axisIterator(Axis.NAMESPACE);
while (nsIter.hasNext()) {
XdmNode ns = (XdmNode) nsIter.next();
QName prefix = ns.getNodeName();
localBindings.put(prefix == null ? "" : prefix.getLocalName(),ns.getStringValue());
}
} catch (SaxonApiException sae) {
throw new XProcException(sae);
}
} else if (nsbinding.getNamespaceBindings() != null) {
Hashtable<String,String> bindings = nsbinding.getNamespaceBindings();
for (String prefix : bindings.keySet()) {
if ("".equals(prefix) || prefix == null) {
// nop; the default namespace never plays a role in XPath expression evaluation
} else {
localBindings.put(prefix,bindings.get(prefix));
}
}
}
// Remove the excluded ones
HashSet<String> prefixes = new HashSet<String> ();
for (String uri : nsbinding.getExcludedNamespaces()) {
for (String prefix : localBindings.keySet()) {
if (uri.equals(localBindings.get(prefix))) {
prefixes.add(prefix);
}
}
}
for (String prefix : prefixes) {
localBindings.remove(prefix);
}
// Add them to the bindings for this value, making sure there are no errors...
for (String pfx : localBindings.keySet()) {
if (nsBindings.containsKey(pfx) && !nsBindings.get(pfx).equals(localBindings.get(pfx))) {
throw XProcException.dynamicError(13);
}
nsBindings.put(pfx,localBindings.get(pfx));
}
}
String select = var.getSelect();
Vector<XdmItem> results = evaluateXPath(doc, nsBindings, select, globals);
String value = "";
try {
for (XdmItem item : results) {
if (item.isAtomicValue()) {
value += item.getStringValue();
} else {
XdmNode node = (XdmNode) item;
if (node.getNodeKind() == XdmNodeKind.ATTRIBUTE
|| node.getNodeKind() == XdmNodeKind.NAMESPACE) {
value += node.getStringValue();
} else {
XdmDestination dest = new XdmDestination();
S9apiUtils.writeXdmValue(runtime,item,dest,null);
value += dest.getXdmNode().getStringValue();
}
}
}
} catch (SaxonApiUncheckedException saue) {
Throwable sae = saue.getCause();
if (sae instanceof XPathException) {
XPathException xe = (XPathException) sae;
if ("http://www.w3.org/2005/xqt-errors".equals(xe.getErrorCodeNamespace()) && "XPDY0002".equals(xe.getErrorCodeLocalPart())) {
throw XProcException.dynamicError(26, step.getNode(), "The expression for $" + var.getName() + " refers to the context item.");
} else {
throw saue;
}
} else {
throw saue;
}
} catch (SaxonApiException sae) {
throw new XProcException(sae);
}
// Now test to see if the option is a reasonable value
if (var.getType() != null) {
String type = var.getType();
if (type.contains("|")) {
TypeUtils.checkLiteral(value, type);
} else if (type.contains(":")) {
TypeUtils.checkType(runtime, value, var.getTypeAsQName(), var.getNode());
}
}
// Section 5.7.5 Namespaces on variables, options, and parameters
//
// If the select attribute was used to specify the value and it consisted of a single VariableReference
// (per [XPath 1.0] or [XPath 2.0], as appropriate), then the namespace bindings from the referenced
// option or variable are used.
Pattern varrefpat = Pattern.compile("^\\s*\\$([^\\s=]+)\\s*$");
Matcher varref = varrefpat.matcher(select);
if (varref.matches()) {
String varrefstr = varref.group(1);
QName varname = null;
if (varrefstr.contains(":")) {
String vpfx = varrefstr.substring(0, varrefstr.indexOf(":"));
String vlocal = varrefstr.substring(varrefstr.indexOf(":")+1);
String vns = nsBindings.get(vpfx);
varname = new QName(vpfx, vns, vlocal);
} else {
varname = new QName("", varrefstr);
}
RuntimeValue val = globals.get(varname);
nsBindings = val.getNamespaceBindings();
}
// Section 5.7.5 Namespaces on variables, options, and parameters
//
// If the select attribute was used to specify the value and it evaluated to a node-set, then the in-scope
// namespaces from the first node in the selected node-set (or, if it's not an element, its parent) are used.
if (results.size() > 0 && results.get(0) instanceof XdmNode) {
XdmNode node = (XdmNode) results.get(0);
nsBindings.clear();
XdmSequenceIterator nsIter = node.axisIterator(Axis.NAMESPACE);
while (nsIter.hasNext()) {
XdmNode ns = (XdmNode) nsIter.next();
nsBindings.put((ns.getNodeName()==null ? "" : ns.getNodeName().getLocalName()),ns.getStringValue());
}
}
if (runtime.getAllowGeneralExpressions()) {
return new RuntimeValue(value,results,var.getNode(),nsBindings);
} else {
return new RuntimeValue(value,var.getNode(),nsBindings);
}
}