Example usage for org.dom4j Namespace getURI

List of usage examples for org.dom4j Namespace getURI

Introduction

In this page you can find the example usage for org.dom4j Namespace getURI.

Prototype

public String getURI() 

Source Link

Document

DOCUMENT ME!

Usage

From source file:org.nuxeo.ecm.jsf2.migration.parser.NamespaceParser.java

License:Open Source License

@Override
public void migrate(Document input) throws Exception {
    Element root = input.getRootElement();
    for (String prefix : listPrefixToMigrate) {
        Namespace newNamespace = new Namespace(prefix, EnumPrefixes.getPrefix(prefix).getNamespace());
        Namespace oldNamespace = root.getNamespaceForPrefix(prefix);
        if (oldNamespace != null) {
            root.remove(oldNamespace);//from w ww . ja v  a 2s. com
        }
        root.add(newNamespace);

        // Change the name of every elements with the prefix
        StringBuilder prefixXpath = new StringBuilder("//");
        prefixXpath.append(prefix);
        prefixXpath.append(":*");
        // Create a new XPath expression, with the old namespace in order
        // to
        // get the elements matching the expression
        XPath xpath = new Dom4jXPath(prefixXpath.toString());
        SimpleNamespaceContext nc = new SimpleNamespaceContext();
        nc.addNamespace(prefix, oldNamespace.getURI());
        xpath.setNamespaceContext(nc);

        @SuppressWarnings("unchecked")
        List<Element> elementsToMigrate = xpath.selectNodes(input);
        for (Element element : elementsToMigrate) {
            // The namespace to change is not hold by the element but the
            // QName
            QName qname = element.getQName();
            QName newQName = new QName(qname.getName(), newNamespace, qname.getQualifiedName());
            element.setQName(newQName);
        }
    }
}

From source file:org.olat.fileresource.types.ScormCPFileResource.java

License:Apache License

/**
 * Check for title and at least one resource.
 * //from  w  ww .  ja v a 2s  .c  o m
 * @param unzippedDir
 * @return True if is of type.
 */
public static boolean validate(final File unzippedDir) throws AddingResourceException {
    final File fManifest = new File(unzippedDir, "imsmanifest.xml");
    final Document doc = IMSLoader.loadIMSDocument(fManifest);
    // do not throw exception already here, as it might be only a generic zip file
    if (doc == null) {
        return false;
    }

    String adluri = null;
    String seqencingUri = null;
    String simpleSeqencingUri = null;
    // get all organization elements. need to set namespace
    final Element rootElement = doc.getRootElement();
    final String nsuri = rootElement.getNamespace().getURI();
    // look for the adl cp namespace that differs a scorm package from a normal cp package
    final Namespace nsADL = rootElement.getNamespaceForPrefix("adlcp");
    if (nsADL != null) {
        adluri = nsADL.getURI();
    }
    final Namespace nsADLSeq = rootElement.getNamespaceForPrefix("adlseq");
    if (nsADLSeq != null) {
        seqencingUri = nsADLSeq.getURI();
    }
    final Namespace nsADLSS = rootElement.getNamespaceForPrefix("imsss");
    if (nsADLSS != null) {
        simpleSeqencingUri = nsADLSS.getURI();
    }
    // we can only support scorm 1.2 so far.
    if (adluri != null
            && !((adluri.indexOf("adlcp_rootv1p2") != -1) || (adluri.indexOf("adlcp_rootv1p3") != -1))) {
        // we dont have have scorm 1.2 or 1.3 namespace so it can't be a scorm package
        throw new AddingResourceException("scorm.no.scorm.namespace");
    }

    final Map nsuris = new HashMap(5);
    nsuris.put("ns", nsuri);
    nsuris.put("adluri", adluri);
    // we might have a scorm 2004 which we do not yet support
    if (seqencingUri != null) {
        nsuris.put("adlseq", seqencingUri);
    }
    if (simpleSeqencingUri != null) {
        nsuris.put("imsss", simpleSeqencingUri);
    }

    // Check for organiztaion element. Must provide at least one... title gets ectracted from either
    // the (optional) <title> element or the mandatory identifier attribute.
    // This makes sure, at least a root node gets created in CPManifestTreeModel.
    final XPath meta = rootElement.createXPath("//ns:organization");
    meta.setNamespaceURIs(nsuris);
    final Element orgaEl = (Element) meta.selectSingleNode(rootElement); // TODO: accept several organizations?
    if (orgaEl == null) {
        throw new AddingResourceException("resource.no.organisation");
    }

    // Check for at least one <item> element referencing a <resource> of adlcp:scormtype="sco" or "asset",
    // which will serve as an entry point.
    final XPath resourcesXPath = rootElement.createXPath("//ns:resources");
    resourcesXPath.setNamespaceURIs(nsuris);
    final Element elResources = (Element) resourcesXPath.selectSingleNode(rootElement);
    if (elResources == null) {
        throw new AddingResourceException("resource.no.resource"); // no <resources> element.
    }
    final XPath itemsXPath = rootElement.createXPath("//ns:item");
    itemsXPath.setNamespaceURIs(nsuris);
    final List items = itemsXPath.selectNodes(rootElement);
    if (items.size() == 0) {
        throw new AddingResourceException("scorm.no.item"); // no <item> element.
    }

    // check for scorm 2004 simple sequencing stuff which we do not yet support
    if (seqencingUri != null) {
        final XPath seqencingXPath = rootElement.createXPath("//ns:imsss");
        final List sequences = seqencingXPath.selectNodes(rootElement);
        if (sequences.size() > 0) {
            throw new AddingResourceException("scorm.found.seqencing"); // seqencing elements found -> scorm 2004
        }
    }

    final Set set = new HashSet();
    for (final Iterator iter = items.iterator(); iter.hasNext();) {
        final Element item = (Element) iter.next();
        final String identifier = item.attributeValue("identifier");
        // check if identifiers are unique, reject if not so
        if (!set.add(identifier)) {
            throw new AddingResourceException("resource.general.error");// TODO:create special error message for non unique ids
        }
    }

    for (final Iterator iter = items.iterator(); iter.hasNext();) {
        final Element item = (Element) iter.next();
        final String identifierref = item.attributeValue("identifierref");
        if (identifierref == null) {
            continue;
        }
        final XPath resourceXPath = rootElement
                .createXPath("//ns:resource[@identifier='" + identifierref + "']");
        resourceXPath.setNamespaceURIs(nsuris);
        final Element elResource = (Element) resourceXPath.selectSingleNode(elResources);
        if (elResource == null) {
            throw new AddingResourceException("resource.no.matching.resource");
        }
        // check for scorm attribute
        final Attribute scormAttr = elResource.attribute("scormtype");
        // some packages have attribute written like "scormType"
        final Attribute scormAttrUpper = elResource.attribute("scormType");
        if (scormAttr == null && scormAttrUpper == null) {
            throw new AddingResourceException("scorm.no.attribute.scormtype");
        }
        String attr = "";
        if (scormAttr != null) {
            attr = scormAttr.getStringValue();
        }
        if (scormAttrUpper != null) {
            attr = scormAttrUpper.getStringValue();
        }
        if (attr == null) {
            throw new AddingResourceException("scorm.no.attribute.value");
        }
        if (elResource.attributeValue("href") != null
                && (attr.equalsIgnoreCase("sco") || attr.equalsIgnoreCase("asset"))) {
            return true; // success.
        }
    }
    throw new AddingResourceException("resource.general.error");
}

From source file:org.openadaptor.auxil.convertor.map.DocumentMapFacade.java

License:Open Source License

/**
 * Extract namespace information from the root element of the document. Apply the default
 * prefix to the default namespace if there is one.
 * @param document//from   ww  w .  jav  a  2  s  . c  o m
 */
private void cacheNamespaces(Document document) {
    nsMap = new HashMap();
    Namespace ns = document.getRootElement().getNamespace();
    nsMap.put(getDefaultNamespacePrefix(), ns.getURI());
    log.debug("Default Namespace: prefix= [" + getDefaultNamespacePrefix() + "] URI= [" + ns.getURI() + "]");

    List additionalNamespaces = document.getRootElement().additionalNamespaces();
    Iterator nsIter = additionalNamespaces.iterator();
    while (nsIter.hasNext()) {
        Namespace nextNS = (Namespace) nsIter.next();
        nsMap.put(nextNS.getPrefix(), nextNS.getURI());
        log.debug("Next Namespace: prefix= [" + nextNS.getPrefix() + "] URI= [" + nextNS.getURI() + "]");
    }
}

From source file:org.openxml4j.opc.internal.unmarshallers.PackagePropertiesUnmarshaller.java

License:Apache License

/**
 * Check the element for the following OPC compliance rules:
 * //from w  ww .  j av  a2s. co m
 * Rule M4.2: A format consumer shall consider the use of the Markup
 * Compatibility namespace to be an error.
 * 
 * Rule M4.3: Producers shall not create a document element that contains
 * refinements to the Dublin Core elements, except for the two specified in
 * the schema: <dcterms:created> and <dcterms:modified> Consumers shall
 * consider a document element that violates this constraint to be an error.
 * 
 * Rule M4.4: Producers shall not create a document element that contains
 * the xml:lang attribute. Consumers shall consider a document element that
 * violates this constraint to be an error.
 * 
 * Rule M4.5: Producers shall not create a document element that contains
 * the xsi:type attribute, except for a <dcterms:created> or
 * <dcterms:modified> element where the xsi:type attribute shall be present
 * and shall hold the value dcterms:W3CDTF, where dcterms is the namespace
 * prefix of the Dublin Core namespace. Consumers shall consider a document
 * element that violates this constraint to be an error.
 */
public void checkElementForOPCCompliance(Element el) throws InvalidFormatException {
    // Check the current element
    List declaredNamespaces = el.declaredNamespaces();
    Iterator itNS = declaredNamespaces.iterator();
    while (itNS.hasNext()) {
        Namespace ns = (Namespace) itNS.next();

        // Rule M4.2
        if (ns.getURI().equals(PackageNamespaces.MARKUP_COMPATIBILITY))
            throw new InvalidFormatException(
                    "OPC Compliance error [M4.2]: A format consumer shall consider the use of the Markup Compatibility namespace to be an error.");
    }

    // Rule M4.3
    if (el.getNamespace().getURI().equals(PackageProperties.NAMESPACE_DCTERMS)
            && !(el.getName().equals(KEYWORD_CREATED) || el.getName().equals(KEYWORD_MODIFIED)))
        throw new InvalidFormatException(
                "OPC Compliance error [M4.3]: Producers shall not create a document element that contains refinements to the Dublin Core elements, except for the two specified in the schema: <dcterms:created> and <dcterms:modified> Consumers shall consider a document element that violates this constraint to be an error.");

    // Rule M4.4
    if (el.attribute(new QName("lang", namespaceXML)) != null)
        throw new InvalidFormatException(
                "OPC Compliance error [M4.4]: Producers shall not create a document element that contains the xml:lang attribute. Consumers shall consider a document element that violates this constraint to be an error.");

    // Rule M4.5
    if (el.getNamespace().getURI().equals(PackageProperties.NAMESPACE_DCTERMS)) {
        // DCTerms namespace only use with 'created' and 'modified' elements
        String elName = el.getName();
        if (!(elName.equals(KEYWORD_CREATED) || elName.equals(KEYWORD_MODIFIED)))
            throw new InvalidFormatException("Namespace error : " + elName
                    + " shouldn't have the following naemspace -> " + PackageProperties.NAMESPACE_DCTERMS);

        // Check for the 'xsi:type' attribute
        Attribute typeAtt = el.attribute(new QName("type", namespaceXSI));
        if (typeAtt == null)
            throw new InvalidFormatException("The element '" + elName + "' must have the '"
                    + namespaceXSI.getPrefix() + ":type' attribute present !");

        // Check for the attribute value => 'dcterms:W3CDTF'
        if (!typeAtt.getValue().equals("dcterms:W3CDTF"))
            throw new InvalidFormatException("The element '" + elName + "' must have the '"
                    + namespaceXSI.getPrefix() + ":type' attribute with the value 'dcterms:W3CDTF' !");
    }

    // Check its children
    Iterator itChildren = el.elementIterator();
    while (itChildren.hasNext())
        checkElementForOPCCompliance((Element) itChildren.next());
}

From source file:org.orbeon.oxf.processor.tamino.dom4j.TDOM4JNamespaceStack.java

License:Open Source License

/**
**  This will add a new namespace to the current available stack.
**
** @param ns Namespace to add./*w  w  w.j  a v  a  2 s  .  c om*/
**/
public void push(Namespace ns) {
    prefixes.push(ns.getPrefix());
    uris.push(ns.getURI());
}

From source file:org.orbeon.oxf.processor.tamino.dom4j.TDOM4JXMLOutputter.java

License:Open Source License

/**
* <p>/* w ww .  ja  v a 2s . co  m*/
* This will handle printing out an <code>{@link Element}</code>,
*   its <code>{@link Attribute}</code>s, and its value.
* </p>
*
* @param element <code>Element</code> to output.
* @param out <code>Writer</code> to write to.
* @param indent <code>int</code> level of indention.
* @param namespaces <code>List</code> stack of Namespaces in scope.
*/
protected void printElement(Element element, Writer out, int indentLevel, TDOM4JNamespaceStack namespaces)
        throws IOException {

    List mixedContent = element.elements();

    boolean empty = mixedContent.size() == 0;
    boolean stringOnly = !empty && mixedContent.size() == 1 && mixedContent.get(0) instanceof String;

    // Print beginning element tag
    /* maybe the doctype, xml declaration, and processing instructions
     should only break before and not after; then this check is
     unnecessary, or maybe the println should only come after and
     never before.  Then the output always ends with a newline */

    indent(out, indentLevel);

    // Print the beginning of the tag plus attributes and any
    // necessary namespace declarations
    out.write("<");
    out.write(element.getQualifiedName());
    int previouslyDeclaredNamespaces = namespaces.size();

    Namespace ns = element.getNamespace();

    // Add namespace decl only if it's not the XML namespace and it's
    // not the NO_NAMESPACE with the prefix "" not yet mapped
    // (we do output xmlns="" if the "" prefix was already used and we
    // need to reclaim it for the NO_NAMESPACE)
    if (ns != Namespace.XML_NAMESPACE && !(ns == Namespace.NO_NAMESPACE && namespaces.getURI("") == null)) {
        String prefix = ns.getPrefix();
        String uri = namespaces.getURI(prefix);
        if (!ns.getURI().equals(uri)) { // output a new namespace decl
            namespaces.push(ns);
            printNamespace(ns, out);
        }
    }

    // Print out additional namespace declarations
    List additionalNamespaces = element.additionalNamespaces();
    if (additionalNamespaces != null) {
        for (int i = 0; i < additionalNamespaces.size(); i++) {
            Namespace additional = (Namespace) additionalNamespaces.get(i);
            String prefix = additional.getPrefix();
            String uri = namespaces.getURI(prefix);
            if (!additional.getURI().equals(uri)) {
                namespaces.push(additional);
                printNamespace(additional, out);
            }
        }
    }

    printAttributes(element.attributes(), element, out, namespaces);

    // handle "" string same as empty
    if (stringOnly) {
        String elementText = trimText ? element.getTextTrim() : element.getText();
        if (elementText == null || elementText.equals("")) {
            empty = true;
        }
    }

    if (empty) {
        // Simply close up
        if (!expandEmptyElements) {
            out.write(" />");
        } else {
            out.write("></");
            out.write(element.getQualifiedName());
            out.write(">");
        }
        maybePrintln(out);
    } else {
        // we know it's not null or empty from above
        out.write(">");

        if (stringOnly) {
            // if string only, print content on same line as tags
            printElementContent(element, out, indentLevel, namespaces, mixedContent);
        } else {
            maybePrintln(out);
            printElementContent(element, out, indentLevel, namespaces, mixedContent);
            indent(out, indentLevel);
        }

        out.write("</");
        out.write(element.getQualifiedName());
        out.write(">");

        maybePrintln(out);
    }

    // remove declared namespaces from stack
    while (namespaces.size() > previouslyDeclaredNamespaces) {
        namespaces.pop();
    }
}

From source file:org.orbeon.oxf.processor.tamino.dom4j.TDOM4JXMLOutputter.java

License:Open Source License

/**
* <p>/*from w  w  w. j a va2 s. c  o  m*/
*  This will handle printing out any needed <code>{@link Namespace}</code>
*    declarations.
* </p>
*
* @param ns <code>Namespace</code> to print definition of
* @param out <code>Writer</code> to write to.
*/
protected void printNamespace(Namespace ns, Writer out) throws IOException {
    out.write(" xmlns");
    String prefix = ns.getPrefix();
    if (!prefix.equals("")) {
        out.write(":");
        out.write(prefix);
    }
    out.write("=\"");
    out.write(ns.getURI());
    out.write("\"");
}

From source file:org.orbeon.oxf.processor.tamino.dom4j.TDOM4JXMLOutputter.java

License:Open Source License

/**
* <p>//from w  ww .j a  v  a  2s  .co  m
* This will handle printing out an <code>{@link Attribute}</code> list.
* </p>
*
* @param attributes <code>List</code> of Attribute objcts
* @param out <code>Writer</code> to write to
*/
protected void printAttributes(List attributes, Element parent, Writer out, TDOM4JNamespaceStack namespaces)
        throws IOException {

    // I do not yet handle the case where the same prefix maps to
    // two different URIs. For attributes on the same element
    // this is illegal; but as yet we don't throw an exception
    // if someone tries to do this
    Set prefixes = new HashSet();

    for (int i = 0, size = attributes.size(); i < size; i++) {
        Attribute attribute = (Attribute) attributes.get(i);
        Namespace ns = attribute.getNamespace();
        if (ns != Namespace.NO_NAMESPACE && ns != Namespace.XML_NAMESPACE) {
            String prefix = ns.getPrefix();
            String uri = namespaces.getURI(prefix);
            if (!ns.getURI().equals(uri)) { // output a new namespace decl
                printNamespace(ns, out);
                namespaces.push(ns);
            }
        }

        out.write(" ");
        out.write(attribute.getQualifiedName());
        out.write("=");

        out.write("\"");
        out.write(escapeAttributeEntities(attribute.getValue()));
        out.write("\"");
    }

}

From source file:org.orbeon.oxf.processor.tamino.dom4j.TDOM4JXMLOutputter.java

License:Open Source License

/**
 ** Gets all the declared namespaces starting at the given element and accumulates the detected namespaces
 ** within the given namespace stack. The given namespace stack is also returned as the result.
 ** Please note, that this method has been added for the purpose that not always all given namespaces
 ** are serialized if they are already given for an ancestor.
 **///from  w  w  w.ja va2 s.  co m
private TDOM4JNamespaceStack getParentNamespaces(Element element, TDOM4JNamespaceStack namespaces) {

    if (element == null)
        return namespaces;

    if (element.getParent() != null)
        namespaces = getParentNamespaces(element.getParent(), namespaces);

    Namespace ns = element.getNamespace();

    // Add namespace decl only if it's not the XML namespace and it's
    // not the NO_NAMESPACE with the prefix "" not yet mapped
    // (we do output xmlns="" if the "" prefix was already used and we
    // need to reclaim it for the NO_NAMESPACE)
    if (ns != Namespace.XML_NAMESPACE && !(ns == Namespace.NO_NAMESPACE && namespaces.getURI("") == null)) {
        String prefix = ns.getPrefix();
        String uri = namespaces.getURI(prefix);
        // Put a new namespace declaratation into the namespace stack
        if (!ns.getURI().equals(uri)) {
            namespaces.push(ns);
        }
    }

    // Add additional namespace declarations if not given yet
    List additionalNamespaces = element.additionalNamespaces();
    if (additionalNamespaces != null) {
        for (int i = 0; i < additionalNamespaces.size(); i++) {
            Namespace additional = (Namespace) additionalNamespaces.get(i);
            String prefix = additional.getPrefix();
            String uri = namespaces.getURI(prefix);
            if (!additional.getURI().equals(uri))
                namespaces.push(additional);
        }
    }

    return namespaces;

}

From source file:org.orbeon.oxf.transformer.xupdate.statement.Utils.java

License:Open Source License

/**
 * Evaluates an XPath expression//from  w  w  w  .  j av  a  2  s .co m
 */
public static Object evaluate(final URIResolver uriResolver, Object context,
        final VariableContextImpl variableContext, final DocumentContext documentContext,
        final LocationData locationData, String select, NamespaceContext namespaceContext) {
    FunctionContext functionContext = new FunctionContext() {
        public org.jaxen.Function getFunction(final String namespaceURI, final String prefix,
                final String localName) {

            // Override document() and doc()
            if (/*namespaceURI == null &&*/ ("document".equals(localName) || "doc".equals(localName))) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        try {
                            String url = (String) Dom4jUtils.createXPath("string(.)").evaluate(args.get(0));
                            Document result = documentContext.getDocument(url);
                            if (result == null) {
                                Source source = uriResolver.resolve(url, locationData.getSystemID());
                                if (!(source instanceof SAXSource))
                                    throw new ValidationException("Unsupported source type", locationData);
                                XMLReader xmlReader = ((SAXSource) source).getXMLReader();
                                LocationSAXContentHandler contentHandler = new LocationSAXContentHandler();
                                xmlReader.setContentHandler(contentHandler);
                                xmlReader.parse(new InputSource());
                                result = contentHandler.getDocument();
                                documentContext.addDocument(url, result);
                            }
                            return result;
                        } catch (Exception e) {
                            throw new ValidationException(e, locationData);
                        }
                    }
                };
            } else if (/*namespaceURI == null &&*/ "get-namespace-uri-for-prefix".equals(localName)) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        String prefix = (String) Dom4jUtils.createXPath("string(.)").evaluate(args.get(0));
                        Element element = null;
                        if (args.get(1) instanceof List) {
                            List list = (List) args.get(1);
                            if (list.size() == 1)
                                element = (Element) list.get(0);
                        } else if (args.get(1) instanceof Element) {
                            element = (Element) args.get(1);
                        }
                        if (element == null)
                            throw new ValidationException("An element is expected as the second argument "
                                    + "in get-namespace-uri-for-prefix()", locationData);
                        return element.getNamespaceForPrefix(prefix);
                    }
                };
            } else if (/*namespaceURI == null &&*/ "distinct-values".equals(localName)) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        List originalList = args.get(0) instanceof List ? (List) args.get(0)
                                : Collections.singletonList(args.get(0));
                        List resultList = new ArrayList();
                        XPath stringXPath = Dom4jUtils.createXPath("string(.)");
                        for (Iterator i = originalList.iterator(); i.hasNext();) {
                            Object item = (Object) i.next();
                            String itemString = (String) stringXPath.evaluate(item);
                            if (!resultList.contains(itemString))
                                resultList.add(itemString);
                        }
                        return resultList;
                    }
                };
            } else if (/*namespaceURI == null &&*/ "evaluate".equals(localName)) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        try {
                            if (args.size() != 3) {
                                try {
                                    return XPathFunctionContext.getInstance().getFunction(namespaceURI, prefix,
                                            localName);
                                } catch (UnresolvableException e) {
                                    throw new ValidationException(e, locationData);
                                }
                            } else {
                                String xpathString = (String) Dom4jUtils.createXPath("string(.)")
                                        .evaluate(args.get(0));
                                XPath xpath = Dom4jUtils.createXPath(xpathString);
                                Map namespaceURIs = new HashMap();
                                List namespaces = (List) args.get(1);
                                for (Iterator i = namespaces.iterator(); i.hasNext();) {
                                    org.dom4j.Namespace namespace = (org.dom4j.Namespace) i.next();
                                    namespaceURIs.put(namespace.getPrefix(), namespace.getURI());
                                }
                                xpath.setNamespaceURIs(namespaceURIs);
                                return xpath.evaluate(args.get(2));
                            }
                        } catch (InvalidXPathException e) {
                            throw new ValidationException(e, locationData);
                        }
                    }
                };
            } else if (/*namespaceURI == null &&*/ "tokenize".equals(localName)) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        try {
                            String input = (String) Dom4jUtils.createXPath("string(.)").evaluate(args.get(0));
                            String pattern = (String) Dom4jUtils.createXPath("string(.)").evaluate(args.get(1));
                            List result = new ArrayList();
                            while (input.length() != 0) {
                                int position = input.indexOf(pattern);
                                if (position != -1) {
                                    result.add(input.substring(0, position));
                                    input = input.substring(position + 1);
                                } else {
                                    result.add(input);
                                    input = "";
                                }
                            }
                            return result;
                        } catch (InvalidXPathException e) {
                            throw new ValidationException(e, locationData);
                        }
                    }
                };
            } else if (/*namespaceURI == null &&*/ "string-join".equals(localName)) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        try {
                            List strings = (List) args.get(0);
                            String pattern = (String) Dom4jUtils.createXPath("string(.)").evaluate(args.get(1));
                            StringBuilder result = new StringBuilder();
                            boolean isFirst = true;
                            for (Iterator i = strings.iterator(); i.hasNext();) {
                                if (!isFirst)
                                    result.append(pattern);
                                else
                                    isFirst = false;
                                String item = (String) (String) Dom4jUtils.createXPath("string(.)")
                                        .evaluate(i.next());
                                result.append(item);
                            }
                            return result.toString();
                        } catch (InvalidXPathException e) {
                            throw new ValidationException(e, locationData);
                        }
                    }
                };
            } else if (/*namespaceURI == null &&*/ "reverse".equals(localName)) {
                return new org.jaxen.Function() {
                    public Object call(Context jaxenContext, List args) {
                        try {
                            List result = new ArrayList((List) args.get(0));
                            Collections.reverse(result);
                            return result;
                        } catch (InvalidXPathException e) {
                            throw new ValidationException(e, locationData);
                        }
                    }
                };
            } else {
                try {
                    // Go through standard XPath functions
                    return XPathFunctionContext.getInstance().getFunction(namespaceURI, prefix, localName);
                } catch (UnresolvableException e) {
                    // User-defined function
                    try {
                        final Closure closure = findClosure(
                                variableContext.getVariableValue(namespaceURI, prefix, localName));
                        if (closure == null)
                            throw new ValidationException(
                                    "'" + qualifiedName(prefix, localName) + "' is not a function",
                                    locationData);
                        return new org.jaxen.Function() {
                            public Object call(Context context, List args) {
                                return closure.execute(args);
                            }
                        };
                    } catch (UnresolvableException e2) {
                        throw new ValidationException("Cannot invoke function '"
                                + qualifiedName(prefix, localName) + "', no such function", locationData);
                    }
                }
            }
        }

        private Closure findClosure(Object xpathObject) {
            if (xpathObject instanceof Closure) {
                return (Closure) xpathObject;
            } else if (xpathObject instanceof List) {
                for (Iterator i = ((List) xpathObject).iterator(); i.hasNext();) {
                    Closure closure = findClosure(i.next());
                    if (closure != null)
                        return closure;
                }
                return null;
            } else {
                return null;
            }
        }
    };

    try {
        // Create XPath
        XPath xpath = Dom4jUtils.createXPath(select);

        // Set variable, namespace, and function context
        if (context instanceof Context) {
            // Create a new context, as Jaxen may modify the current node in the context (is this a bug?)
            Context currentContext = (Context) context;
            Context newContext = new Context(new ContextSupport(namespaceContext, functionContext,
                    variableContext, DocumentNavigator.getInstance()));
            newContext.setNodeSet(currentContext.getNodeSet());
            newContext.setSize(currentContext.getSize());
            newContext.setPosition(currentContext.getPosition());
            context = newContext;
        } else {
            xpath.setVariableContext(variableContext);
            xpath.setNamespaceContext(namespaceContext);
            xpath.setFunctionContext(functionContext);
        }

        // Execute XPath
        return xpath.evaluate(context);
    } catch (Exception e) {
        throw new ValidationException(e, locationData);
    }
}