001: package gnu.xquery.util;
002:
003: import gnu.mapping.*;
004: import gnu.xml.*;
005: import gnu.kawa.xml.*;
006: import gnu.text.*;
007:
008: public class QNameUtils {
009: public static Object resolveQNameUsingElement(Object qname,
010: KElement node) {
011: qname = KNode.atomicValue(qname);
012: if (qname == Values.empty || qname == null)
013: return qname;
014: if (qname instanceof Values
015: || !(qname instanceof String || qname instanceof UntypedAtomic))
016: throw new RuntimeException("bad argument to QName");
017: String name = TextUtils.replaceWhitespace(qname.toString(),
018: true);
019: int colon = name.indexOf(':');
020: String prefix, localPart, uri;
021: if (colon < 0) {
022: prefix = null;
023: localPart = name;
024: } else {
025: prefix = name.substring(0, colon).intern();
026: localPart = name.substring(colon + 1);
027: }
028: uri = node.lookupNamespaceURI(prefix);
029: if (uri == null) {
030: if (prefix == null)
031: uri = "";
032: else
033: throw new RuntimeException("unknown namespace for '"
034: + name + "'");
035: }
036: if (!validNCName(localPart)
037: || (prefix != null && !validNCName(prefix))) {
038: throw new RuntimeException("invalid QName syntax '" + name
039: + "'");
040: }
041: return Symbol
042: .make(uri, localPart, prefix == null ? "" : prefix);
043: }
044:
045: /** Method called from compiled code to "cast" to a QName.
046: * @param qname The value to cast to QName.
047: * @param constructorNamespaces Namespace bindings from namespace
048: * attributes in direct element constructors.
049: * @param prologNamespaces Namespac bindings from query prolog,
050: * as well as builtin namespace prefixes.
051: */
052: public static Object resolveQName(Object qname,
053: NamespaceBinding constructorNamespaces,
054: NamespaceBinding prologNamespaces) {
055: qname = KNode.atomicValue(qname);
056: if (qname instanceof Symbol)
057: return qname;
058: if (qname instanceof Values
059: || !(qname instanceof String || qname instanceof UntypedAtomic))
060: throw new RuntimeException("bad argument to QName");
061: String name = TextUtils.replaceWhitespace(qname.toString(),
062: true);
063: int colon = name.indexOf(':');
064: String prefix, localPart;
065: if (colon < 0) {
066: localPart = name;
067: prefix = null;
068: } else {
069: prefix = name.substring(0, colon).intern();
070: localPart = name.substring(colon + 1);
071: }
072: if (!validNCName(localPart)
073: || (prefix != null && !validNCName(prefix))) {
074: throw new RuntimeException("invalid QName syntax '" + name
075: + "'");
076: }
077: String uri = resolvePrefix(prefix, constructorNamespaces,
078: prologNamespaces);
079: return Symbol
080: .make(uri, localPart, prefix == null ? "" : prefix);
081: }
082:
083: /** Search for a uri matching the given prefix.
084: * @return uri or null if there is no binding for prefix.
085: */
086: public static String lookupPrefix(String prefix,
087: NamespaceBinding constructorNamespaces,
088: NamespaceBinding prologNamespaces) {
089: String uri;
090:
091: for (NamespaceBinding ns = constructorNamespaces;; ns = ns
092: .getNext()) {
093: if (ns == null) {
094: uri = prologNamespaces.resolve(prefix);
095: break;
096: }
097: if (ns.getPrefix() == prefix || ns.getUri() == null) {
098: uri = ns.getUri();
099: break;
100: }
101: }
102: if (uri == null && prefix == null)
103: uri = "";
104: return uri;
105: }
106:
107: /** Search for a uri matching the given prefix.
108: * Throw exception if there is no binding and the prefix is non-empty.
109: */
110: public static String resolvePrefix(String prefix,
111: NamespaceBinding constructorNamespaces,
112: NamespaceBinding prologNamespaces) {
113: String uri = lookupPrefix(prefix, constructorNamespaces,
114: prologNamespaces);
115: if (uri == null)
116: throw new RuntimeException("unknown namespace prefix '"
117: + prefix + "'");
118: return uri;
119: }
120:
121: public static boolean validNCName(String name) {
122: return XName.isName(name);
123: }
124:
125: /** This implements the <code>fn:QName</code> standard function. */
126:
127: public static Symbol makeQName(Object paramURI, String paramQName) {
128: if (paramURI == null || paramURI == Values.empty)
129: paramURI = "";
130: int colon = paramQName.indexOf(':');
131: String namespaceURI = (String) paramURI, localPart, prefix;
132: if (colon < 0) {
133: localPart = paramQName;
134: prefix = "";
135: } else {
136: localPart = paramQName.substring(colon + 1);
137: prefix = paramQName.substring(0, colon).intern();
138: }
139: if (!validNCName(localPart)
140: || (colon >= 0 && !validNCName(prefix)))
141: throw new IllegalArgumentException("invalid QName syntax '"
142: + paramQName + "'");
143: if (colon >= 0 && namespaceURI.length() == 0)
144: throw new IllegalArgumentException("empty uri for '"
145: + paramQName + "'");
146: return Symbol.make(namespaceURI, localPart, prefix);
147: }
148:
149: public static Object localNameFromQName(Object name) {
150: if (name == Values.empty || name == null)
151: return name;
152: if (!(name instanceof Symbol))
153: throw new WrongType("local-name-from-QName", 1, name,
154: "xs:QName");
155: return XStringType.makeNCName(((Symbol) name).getName());
156: }
157:
158: public static Object prefixFromQName(Object name) {
159: if (name == Values.empty || name == null)
160: return name;
161: if (name instanceof Symbol) {
162: String prefix = ((Symbol) name).getPrefix();
163: if (prefix == null || prefix.length() == 0)
164: return Values.empty;
165: return XStringType.makeNCName(prefix);
166: }
167: throw new WrongType("prefix-from-QName", 1, name, "xs:QName");
168: }
169:
170: public static Object namespaceURIFromQName(Object name) {
171: if (name == Values.empty || name == null)
172: return name;
173: try {
174: return URIPath.makeURI(((Symbol) name).getNamespaceURI());
175: } catch (ClassCastException ex) {
176: throw new WrongType("namespace-uri", 1, name, "xs:QName");
177: }
178: }
179:
180: public static Object namespaceURIForPrefix(Object prefix,
181: Object element) {
182: KNode el = KNode.coerce(element);
183: if (el == null)
184: throw new WrongType("namespace-uri-for-prefix", 2, element,
185: "node()");
186: String str;
187: if (prefix == null || prefix == Values.empty)
188: str = null;
189: else if (!(prefix instanceof String || prefix instanceof UntypedAtomic))
190: throw new WrongType("namespace-uri-for-prefix", 1, element,
191: "xs:string");
192: else {
193: str = prefix.toString().intern();
194: if (str == "")
195: str = null;
196: }
197: String uri = el.lookupNamespaceURI(str);
198: if (uri == null)
199: return Values.empty;
200: else
201: return uri;
202: }
203:
204: public static Object resolveURI(Object relative, Object base)
205: throws java.net.URISyntaxException {
206: if (relative instanceof KNode)
207: relative = KNode.atomicValue(relative);
208: if (base instanceof KNode)
209: base = KNode.atomicValue(base);
210: if (relative == Values.empty || relative == null)
211: return relative;
212: if (relative instanceof UntypedAtomic)
213: relative = relative.toString();
214: if (base instanceof UntypedAtomic)
215: base = base.toString();
216: Path baseP = base instanceof Path ? (Path) base : URIPath
217: .makeURI(base);
218: if (relative instanceof Path)
219: return baseP.resolve((Path) relative);
220: else
221: return baseP.resolve(relative.toString());
222: }
223: }
|