001: // Copyright (c) 2003 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.xml;
005:
006: import gnu.mapping.*;
007: import java.io.*;
008:
009: /** A QName with namespace nodes [and future optional type annotation]. */
010:
011: public class XName extends Symbol implements Externalizable {
012: NamespaceBinding namespaceNodes;
013:
014: public XName() {
015: }
016:
017: public XName(Symbol symbol, NamespaceBinding namespaceNodes) {
018: super (symbol.getNamespace(), symbol.getName());
019: this .namespaceNodes = namespaceNodes;
020: }
021:
022: /** Namespace nodes associated with an element.
023: * These are in inverse document/parse order.
024: */
025: public final NamespaceBinding getNamespaceNodes() {
026: return namespaceNodes;
027: }
028:
029: public final void setNamespaceNodes(NamespaceBinding nodes) {
030: this .namespaceNodes = nodes;
031: }
032:
033: String lookupNamespaceURI(String prefix) {
034: for (NamespaceBinding ns = namespaceNodes; ns != null; ns = ns.next) {
035: if (prefix == ns.prefix)
036: return ns.uri;
037: }
038: return null;
039: }
040:
041: public void writeExternal(ObjectOutput out) throws IOException {
042: super .writeExternal(out);
043: out.writeObject(namespaceNodes);
044: }
045:
046: public void readExternal(ObjectInput in) throws IOException,
047: ClassNotFoundException {
048: super .readExternal(in);
049: namespaceNodes = (NamespaceBinding) in.readObject();
050: }
051:
052: public static boolean isNameStart(int ch) {
053: /* #ifdef JAVA5 */
054: // return Character.isUnicodeIdentifierStart(ch)
055: /* #else */
056: return ch >= 0x10000
057: || Character.isUnicodeIdentifierStart((char) ch)
058: /* #endif */
059: || ch == '_';
060: }
061:
062: public static boolean isNamePart(int ch) {
063: /* #ifdef JAVA5 */
064: // return Character.isUnicodeIdentifierPart(ch)
065: /* #else */
066: return ch >= 0x10000
067: || Character.isUnicodeIdentifierPart((char) ch)
068: /* #endif */
069: || ch == '-' || ch == '.';
070: }
071:
072: public static boolean isNmToken(String value) {
073: return checkName(value) >= 0;
074: }
075:
076: public static boolean isName(String value) {
077: return checkName(value) > 0;
078: }
079:
080: public static boolean isNCName(String value) {
081: return checkName(value) > 1;
082: }
083:
084: /** Check if a string is a valid NMTOKEN, Name, or NCName.
085: * @return 2 if string is an NCName; otherwise 1 if string is a Name;
086: * otherwise 0 if string is an NMTOKEN; otherwise -1.
087: */
088:
089: public static int checkName(String value) {
090: int len = value.length();
091: if (len == 0)
092: return -1;
093: int result = 2;
094: for (int i = 0; i < len;) {
095: boolean first = i == 0;
096: int ch = value.charAt(i++);
097: if (ch >= 0xD800 && ch < 0xDC00 && i < len)
098: ch = (ch - 0xD800) * 0x400
099: + (value.charAt(i++) - 0xDC00) + 0x10000;
100: if (ch == ':') {
101: if (result == 2)
102: result = 1;
103: } else if (!XName.isNamePart(ch))
104: return -1;
105: else if (first && !XName.isNameStart(ch))
106: result = 0;
107: }
108: return result;
109: }
110: }
|