Package org.exist.xquery.functions.fn

Source Code of org.exist.xquery.functions.fn.FunResolveQName

/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2009 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*  $Id$
*/
package org.exist.xquery.functions.fn;

import java.util.Iterator;

import org.exist.dom.ElementImpl;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
import org.exist.dom.QName;
import org.exist.memtree.NodeImpl;
import org.exist.xquery.BasicFunction;
import org.exist.xquery.Cardinality;
import org.exist.xquery.Dependency;
import org.exist.xquery.ErrorCodes;
import org.exist.xquery.Function;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.Profiler;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.value.EmptySequence;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.FunctionReturnSequenceType;
import org.exist.xquery.value.NodeValue;
import org.exist.xquery.value.QNameValue;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class FunResolveQName extends BasicFunction {

    public final static FunctionSignature signature =
      new FunctionSignature(new QName("resolve-QName", Function.BUILTIN_FUNCTION_NS),
          "Returns an xs:QName value (that is, an expanded-QName) by taking an xs:string that has the lexical " +
          "form of an xs:QName (a string in the form \"prefix:local-name\" or \"local-name\") and resolving it " +
          "using the in-scope namespaces for a given element.\n\nIf $qname does not have the correct lexical " +
          "form for xs:QName an error is raised [err:FOCA0002].\n\nIf $qname is the empty sequence, returns " +
          "the empty sequence.\n\nMore specifically, the function searches the namespace bindings of " +
          "$element for a binding whose name matches the prefix of $qname, or the zero-length string if " +
          "it has no prefix, and constructs an expanded-QName whose local name is taken from the supplied " +
          "$qname, and whose namespace URI is taken from the string value of the namespace binding.\n\n" +
          "If the $qname has a prefix and if there is no namespace binding for $element that matches this " +
          "prefix, then an error is raised [err:FONS0004].\n\nIf the $qname has no prefix, and there is " +
          "no namespace binding for $element corresponding to the default (unnamed) namespace, then the " +
          "resulting expanded-QName has no namespace part.\n\nThe prefix (or absence of a prefix) in the " +
          "supplied $qname argument is retained in the returned expanded-QName.",
          new SequenceType[] {
            new FunctionParameterSequenceType("qname", Type.STRING, Cardinality.ZERO_OR_ONE, "The QName name"),
            new FunctionParameterSequenceType("element", Type.ELEMENT, Cardinality.EXACTLY_ONE, "The element")
          },
          new FunctionReturnSequenceType(Type.QNAME, Cardinality.EXACTLY_ONE, "the QName of $element with lexical form $qname")
      );

    public FunResolveQName(XQueryContext context) {
        super(context, signature);
    }

    public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
        if (context.getProfiler().isEnabled()) {
            context.getProfiler().start(this);
            context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES",
                                          Dependency.getDependenciesName(this.getDependencies()));
            if (contextSequence != null) {
                context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
            }
        }
   
        final Sequence qnameSeq = args[0];
        if (qnameSeq.isEmpty()) {
            return EmptySequence.EMPTY_SEQUENCE;
        } else {
          context.pushInScopeNamespaces();                   
            final String qnameString = args[0].getStringValue();
            if (QName.isQName(qnameString)) {
                String prefix = QName.extractPrefix(qnameString);

                if (prefix == null) {
                    prefix = "";
                }

                String uri = null;

                final NodeValue node = (NodeValue) args[1].itemAt(0);
                if (node.getImplementationType() == NodeValue.PERSISTENT_NODE) {
                    NodeProxy proxy = (NodeProxy) node;
                    final NodeSet ancestors = proxy.getAncestors(contextId, true);
                    for (final Iterator<NodeProxy> i = ancestors.iterator(); i.hasNext();) {
                        proxy = i.next();
                        final ElementImpl e = (ElementImpl) proxy.getNode();
                        uri = findNamespaceURI(e, prefix);
                        if (uri != null) {
                            break;
                        }
                    }
                } else {
                    NodeImpl next = (NodeImpl) node;
                    do {
                        uri = findNamespaceURI((org.exist.memtree.ElementImpl) next, prefix);
                        if (uri != null) {
                            break;
                        } else {
                            next = (NodeImpl) next.getParentNode();
                        }
                    } while (next != null && next.getNodeType() == Node.ELEMENT_NODE);
                }

                if (uri == null && prefix != null && !"".equals(prefix)) {
                    throw new XPathException(this, ErrorCodes.FONS0004, "No namespace found for prefix. No binding for prefix '" + prefix
                                             + "' was found.", args[0]);
                }
                final String localPart = QName.extractLocalName(qnameString);
                final QName qn = new QName(localPart, uri);
                qn.setPrefix(prefix);
       
                final QNameValue result = new QNameValue(context, qn);
                if (context.getProfiler().isEnabled())
                    {context.getProfiler().end(this, "", result);}
               
                context.popInScopeNamespaces();
         
                return result;
            } else {
                throw new XPathException(this, ErrorCodes.FOCA0002, "Invalid lexical value. '" + qnameString
                                         + "' is not a QName.", args[0]);
            }
        }
    }

    /**
     * The method <code>findNamespaceURI</code>
     *
     * @param element an <code>ElementImpl</code> value
     * @param prefix a <code>String</code> value
     * @return a <code>String</code> value
     */
    public String findNamespaceURI(ElementImpl element, String prefix) {
        final String namespaceURI = element.getNamespaceURI();
        if (namespaceURI != null && namespaceURI.length() > 0 && prefix.equals(element.getPrefix())) {
            return namespaceURI;
        }
        if (element.declaresNamespacePrefixes()) {
            for (final Iterator<String> i = element.getPrefixes(); i.hasNext();) {             
                final String elementPrefix = i.next();
                context.declareInScopeNamespace(elementPrefix, element.getNamespaceForPrefix(elementPrefix));
                if (prefix.equals(elementPrefix)) {
                    return element.getNamespaceForPrefix(prefix);
                }
            }
        }
        return null;
    }

    /**
     * The method <code>findNamespaceURI</code>
     *
     * @param element an <code>Element</code> value
     * @param prefix a <code>String</code> value
     * @return a <code>String</code> value
     */
    public static String findNamespaceURI(Element element, String prefix) {
        //TODO how do you get to the declared namespaces on plain elements?
        final String namespaceURI = element.getNamespaceURI();
        if (namespaceURI != null && namespaceURI.length() > 0 && prefix.equals(element.getPrefix())) {
            return namespaceURI;
        } else {
            return null;
        }
    }

    /**
     * The method <code>findNamespaceURI</code>
     *
     * @param element an <code>org.exist.memtree.ElementImpl</code> value
     * @param prefix a <code>String</code> value
     * @return a <code>String</code> value
     */
    public static String findNamespaceURI(org.exist.memtree.ElementImpl element, String prefix) {
        final String namespaceURI = element.getNamespaceURI();
        if (namespaceURI != null && namespaceURI.length() > 0 && prefix.equals(element.getPrefix())) {
            return namespaceURI;
        }
        if (element.declaresNamespacePrefixes()) {
            return (String) element.getNamespaceMap().get(prefix);
        }
        return null;
    }
}
TOP

Related Classes of org.exist.xquery.functions.fn.FunResolveQName

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.