/* * eXist Open Source Native XML Database * Copyright (C) 2001-2007 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.value; import java.text.Collator; import org.exist.dom.QName; import org.exist.xquery.Constants; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; /** * Wrapper class around a {@link org.exist.dom.QName} value which extends * {@link org.exist.xquery.value.AtomicValue}. * * @author wolf */ public class QNameValue extends AtomicValue { private XQueryContext context; private QName qname; private String stringValue; /** * Constructs a new QNameValue by parsing the given name using * the namespace declarations in context. * * @param context * @param name * @throws XPathException */ public QNameValue(XQueryContext context, String name) throws XPathException { if (name.length() == 0) throw new XPathException("err:FORG0001: An empty string is not a valid lexical representation of xs:QName."); this.context = context; try { this.qname = QName.parse(context, name, context.getURIForPrefix("")); } catch (Exception e) { throw new XPathException(e); } stringValue = computeStringValue(); } public QNameValue(XQueryContext context, QName name) { this.context = context; this.qname = name; stringValue = computeStringValue(); } /** * @see org.exist.xquery.value.AtomicValue#getType() */ public int getType() { return Type.QNAME; } /** * Returns the wrapped QName object. */ public QName getQName() { return qname; } /** * @see org.exist.xquery.value.Sequence#getStringValue() */ public String getStringValue() throws XPathException { //TODO : previous approach was to resolve the qname when needed. We now try to keep the original qname return stringValue; } private String computeStringValue() { //TODO : previous approach was to resolve the qname when needed. We now try to keep the original qname String prefix = qname.getPrefix(); //Not clear what to work with here... // WM: Changing the prefix is problematic (e.g. if a module // defines different prefixes than the main module). We should // keep the current in-scope prefix. // if((prefix == null || "".equals(prefix)) && qname.needsNamespaceDecl()) { // prefix = context.getPrefixForURI(qname.getNamespaceURI()); // if (prefix != null) // qname.setPrefix(prefix); // //throw new XPathException( // // "namespace " + qname.getNamespaceURI() + " is not defined"); // // } //TODO : check that the prefix matches the URI in the current context ? if (prefix != null && prefix.length() > 0) return prefix + ':' + qname.getLocalName(); else return qname.getLocalName(); } /** * @see org.exist.xquery.value.Sequence#convertTo(int) */ public AtomicValue convertTo(int requiredType) throws XPathException { switch (requiredType) { case Type.ATOMIC : case Type.ITEM : case Type.QNAME : return this; case Type.STRING : return new StringValue( getStringValue() ); case Type.UNTYPED_ATOMIC : return new UntypedAtomicValue(getStringValue()); default : throw new XPathException( "A QName cannot be converted to " + Type.getTypeName(requiredType)); } } /** * @see org.exist.xquery.value.AtomicValue#compareTo(Collator, int, AtomicValue) */ public boolean compareTo(Collator collator, int operator, AtomicValue other) throws XPathException { if (other.getType() == Type.QNAME) { int cmp = qname.compareTo(((QNameValue) other).qname); switch (operator) { case Constants.EQ : return cmp == 0; case Constants.NEQ : return cmp != 0; /* * QNames are unordered case Constants.GT : return cmp > 0; case Constants.GTEQ : return cmp >= 0; case Constants.LT : return cmp < 0; case Constants.LTEQ : return cmp >= 0; */ default : throw new XPathException("XPTY0004 : cannot apply operator to QName"); } } else throw new XPathException( "Type error: cannot compare QName to " + Type.getTypeName(other.getType())); } /** * @see org.exist.xquery.value.AtomicValue#compareTo(Collator, AtomicValue) */ public int compareTo(Collator collator, AtomicValue other) throws XPathException { if (other.getType() == Type.QNAME) { return qname.compareTo(((QNameValue) other).qname); } else throw new XPathException( "Type error: cannot compare QName to " + Type.getTypeName(other.getType())); } /** * @see org.exist.xquery.value.AtomicValue#max(Collator, AtomicValue) */ public AtomicValue max(Collator collator, AtomicValue other) throws XPathException { throw new XPathException("Invalid argument to aggregate function: QName"); } public AtomicValue min(Collator collator, AtomicValue other) throws XPathException { throw new XPathException("Invalid argument to aggregate function: QName"); } /** * @see org.exist.xquery.value.Item#conversionPreference(java.lang.Class) */ public int conversionPreference(Class javaClass) { if (javaClass.isAssignableFrom(QNameValue.class)) return 0; if (javaClass == String.class) return 1; if (javaClass == Object.class) return 20; return Integer.MAX_VALUE; } /** * @see org.exist.xquery.value.Item#toJavaObject(java.lang.Class) */ public Object toJavaObject(Class target) throws XPathException { if (target.isAssignableFrom(QNameValue.class)) return this; else if (target == String.class) return getStringValue(); else if (target == Object.class) return qname; throw new XPathException( "cannot convert value of type " + Type.getTypeName(getType()) + " to Java object of type " + target.getName()); } public String toString() { try { return this.getStringValue(); } catch (XPathException e) { return super.toString(); } } public boolean effectiveBooleanValue() throws XPathException { throw new XPathException("err:FORG0006: value of type " + Type.getTypeName(getType()) + " has no boolean value."); } }