Source Code Cross Referenced for XMLFilter.java in  » Scripting » Kawa » gnu » xml » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » Kawa » gnu.xml 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // Copyright (c) 2001, 2002, 2003, 2006  Per M.A. Bothner.
0002:        // This is free software;  for terms and warranty disclaimer see ./COPYING.
0003:
0004:        package gnu.xml;
0005:
0006:        import gnu.lists.*;
0007:        import gnu.text.*;
0008:        import gnu.mapping.Symbol; /* #ifdef SAX2 */
0009:        import org.xml.sax.*;
0010:        import gnu.kawa.sax.*; /* #endif */
0011:        import gnu.expr.Keyword; // FIXME - bad cross-package dependency.
0012:
0013:        /** Fixup XML input events.
0014:         * Handles namespace resolution, and adds "namespace nodes" if needed.
0015:         * Does various error checking.
0016:         * This wrapper should be used when creating a NodeTree,
0017:         * as is done for XQuery node constructor expressions.
0018:         * Can also be called directly from XMLParser, in which case we use a slightly
0019:         * lower-level interface where we array char array segments rather than
0020:         * Strings.  This is to avoid duplicate String allocation and interning.
0021:         * The combination XMLParser+XMLFilter+NodeTree makes for a fast and
0022:         * compact way to read an XML file into a DOM.
0023:         */
0024:
0025:        public class XMLFilter implements 
0026:        /* #ifdef SAX2 */
0027:        DocumentHandler, ContentHandler,
0028:        /* #endif */
0029:        gnu.text.SourceLocator, XConsumer, PositionConsumer {
0030:            /** This is where we save attributes while processing a begin element.
0031:             * It may be the final output if {@code out instanceof NodeTree}. */
0032:            TreeList tlist;
0033:
0034:            /** The specified target Consumer that accepts the output.
0035:             * In contrast, base may be either {@code ==out} or {@code ==tlist}. */
0036:            public Consumer out;
0037:
0038:            Consumer base;
0039:
0040:            public static final int COPY_NAMESPACES_PRESERVE = 1;
0041:            public static final int COPY_NAMESPACES_INHERIT = 2;
0042:            public transient int copyNamespacesMode = COPY_NAMESPACES_PRESERVE;
0043:
0044:            /** A helper stack.
0045:             * This is logically multiple separate stacks, but we combine them into
0046:             * a single array.  While this makes the code a little harder to read,
0047:             * it reduces memory overhead and (more importantly) should improve locality.
0048:             * For each nested document or element there is the saved value of
0049:             * namespaceBindings followed by a either a MappingInfo or Symbol
0050:             * from the emitBeginElement/startElement.  This is followed by a MappingInfo
0051:             * or Symbol for each attribute we seen for the current element. */
0052:            Object[] workStack;
0053:            NamespaceBinding namespaceBindings;
0054:
0055:            private SourceMessages messages;
0056:            SourceLocator locator;
0057:            LineBufferedReader in;
0058:
0059:            public void setSourceLocator(LineBufferedReader in) {
0060:                this .in = in;
0061:                this .locator = this ;
0062:            }
0063:
0064:            public void setSourceLocator(SourceLocator locator) {
0065:                this .locator = locator;
0066:            }
0067:
0068:            public void setMessages(SourceMessages messages) {
0069:                this .messages = messages;
0070:            }
0071:
0072:            /** Twice the number of active startElement and startDocument calls. */
0073:            protected int nesting;
0074:
0075:            int previous = 0;
0076:            private static final int SAW_KEYWORD = 1;
0077:            private static final int SAW_WORD = 2;
0078:
0079:            /** If {@code stringizingLevel > 0} then stringize rather than copy nodes.
0080:             * It counts the number of nested startAttributes that are active.
0081:             * (In the future it should also count begun comment and
0082:             * processing-instruction constructors, when those support nesting.) */
0083:            protected int stringizingLevel;
0084:            /** Value of {@code nesting} just before outermost startElement
0085:             * while {@code stringizingLevel > 0}.
0086:             * I.e. if we're nested inside a element nested inside an attribute
0087:             * then {@code stringizingElementNesting >= 0},
0088:             * otherwise {@code stringizingElementNesting == -1}. */
0089:            protected int stringizingElementNesting = -1;
0090:            /** Postive if all output should be ignored.
0091:             * This happens if we're inside an attribute value inside an element which
0092:             * is stringized because it is in turm inside an outer attribute. Phew.
0093:             * If gets increment by nested attributes so we can tell when to stop. */
0094:            protected int ignoringLevel;
0095:
0096:            // List of indexes in tlist.data of begin of attribute.
0097:            int[] startIndexes = null;
0098:
0099:            /** The number of attributes.
0100:             * Zero means we've seen an element start tag.
0101:             * Gets reset to -1 when we no longer in the element header. */
0102:            int attrCount = -1;
0103:
0104:            boolean inStartTag;
0105:
0106:            /** The local name if currently processing an attribute value. */
0107:            String attrLocalName;
0108:            String attrPrefix;
0109:
0110:            /** Non-null if we're processing a namespace declaration attribute.
0111:             * In that case it is the prefix we're defining,
0112:             * or {@code ""} in the case of a default namespace.  */
0113:            String currentNamespacePrefix;
0114:
0115:            /** True if namespace declarations should be passed through as attributes.
0116:             * Like SAX2's http://xml.org/features/namespace-prefixes. */
0117:            public boolean namespacePrefixes = false;
0118:
0119:            /** Map either lexical-QName or expanded-QName to a MappingInfo.
0120:             * This is conceptually three hash tables merged into a single data structure.
0121:             * (1) when we first see a tag (a QName as a lexical form before namespace
0122:             * resolution), we map the tag String to an preliminary info entry that
0123:             * has a null qname field.
0124:             * (2) After see the namespace declaration, we use the same table and keys,
0125:             * but name the uri and qtype.namespaceNodes also have to match.
0126:             * (3) Used for hash-consing NamespaceBindings.
0127:             */
0128:            MappingInfo[] mappingTable = new MappingInfo[128];
0129:            int mappingTableMask = mappingTable.length - 1;
0130:
0131:            boolean mismatchReported;
0132:
0133:            /** Functionally equivalent to
0134:             * {@code new NamespaceBinding(prefix, uri, oldBindings},
0135:             * but uses "hash consing".
0136:             */
0137:            public NamespaceBinding findNamespaceBinding(String prefix,
0138:                    String uri, NamespaceBinding oldBindings) {
0139:                int hash = uri == null ? 0 : uri.hashCode();
0140:                if (prefix != null)
0141:                    hash ^= prefix.hashCode();
0142:                int bucket = hash & mappingTableMask;
0143:                MappingInfo info = mappingTable[bucket];
0144:                for (;; info = info.nextInBucket) {
0145:                    if (info == null) {
0146:                        info = new MappingInfo();
0147:                        info.nextInBucket = mappingTable[bucket];
0148:                        mappingTable[bucket] = info;
0149:                        info.tagHash = hash;
0150:                        info.prefix = prefix;
0151:                        info.local = uri;
0152:                        info.uri = uri;
0153:                        if (uri == "")
0154:                            uri = null;
0155:                        NamespaceBinding namespaces = new NamespaceBinding(
0156:                                prefix, uri, oldBindings);
0157:                        info.namespaces = namespaces;
0158:                        return info.namespaces;
0159:                    }
0160:                    NamespaceBinding namespaces;
0161:                    if (info.tagHash == hash && info.prefix == prefix
0162:                            && (namespaces = info.namespaces) != null
0163:                            && namespaces.getNext() == namespaceBindings
0164:                            && namespaces.getPrefix() == prefix
0165:                            && info.uri == uri) {
0166:                        return info.namespaces;
0167:                    }
0168:                }
0169:            }
0170:
0171:            /** Return a MappingInfo containing a match namespaces.
0172:             * Specifically, return a {@code  MappingInfo info} is such that
0173:             * {@code info.namespaces} is equal to
0174:             * {@code new NamespaceBinding(prefix, uri, oldBindings)}, where {@code uri}
0175:             * is {@code new String(uriChars, uriStart, uriLength).intern())}.
0176:             */
0177:            public MappingInfo lookupNamespaceBinding(String prefix,
0178:                    char[] uriChars, int uriStart, int uriLength, int uriHash,
0179:                    NamespaceBinding oldBindings) {
0180:                int hash = prefix == null ? uriHash : prefix.hashCode()
0181:                        ^ uriHash;
0182:                // Search for a matching already-seen NamespaceBinding list.
0183:                // We hash these to so we can share lists that are equal but
0184:                // appear multiple times in the same XML file, as sometimes happens.
0185:                // This not only saves memory, but keeps hash bucket chains short,
0186:                // which is important since we don't resize the table.
0187:                int bucket = hash & mappingTableMask;
0188:                MappingInfo info = mappingTable[bucket];
0189:                for (;; info = info.nextInBucket) {
0190:                    if (info == null) {
0191:                        info = new MappingInfo();
0192:                        info.nextInBucket = mappingTable[bucket];
0193:                        mappingTable[bucket] = info;
0194:                        String uri = new String(uriChars, uriStart, uriLength)
0195:                                .intern();
0196:                        // We re-use the same MappingInfo table that is mainly used
0197:                        // for tag lookup, but re-interpreting the meaning of the
0198:                        // various fields. Since MappingInfo hashes on prefix^local,
0199:                        // we must do the same here.
0200:                        info.tagHash = hash;
0201:                        info.prefix = prefix;
0202:                        info.local = uri;
0203:                        info.uri = uri;
0204:                        if (uri == "")
0205:                            uri = null;
0206:                        NamespaceBinding namespaces = new NamespaceBinding(
0207:                                prefix, uri, oldBindings);
0208:                        info.namespaces = namespaces;
0209:                        return info;
0210:                    }
0211:                    NamespaceBinding namespaces;
0212:                    if (info.tagHash == hash
0213:                            && info.prefix == prefix
0214:                            && (namespaces = info.namespaces) != null
0215:                            && namespaces.getNext() == namespaceBindings
0216:                            && namespaces.getPrefix() == prefix
0217:                            && MappingInfo.equals(info.uri, uriChars, uriStart,
0218:                                    uriLength)) {
0219:                        return info;
0220:                    }
0221:                }
0222:            }
0223:
0224:            public void endAttribute() {
0225:                if (attrLocalName == null)
0226:                    return;
0227:                if (previous == SAW_KEYWORD) {
0228:                    previous = 0;
0229:                    return;
0230:                }
0231:                if (stringizingElementNesting >= 0)
0232:                    ignoringLevel--;
0233:                if (--stringizingLevel == 0) {
0234:                    if (attrLocalName == "id" && attrPrefix == "xml") {
0235:                        // Need to normalize xml:id attributes.
0236:                        int valStart = startIndexes[attrCount - 1]
0237:                                + TreeList.BEGIN_ATTRIBUTE_LONG_SIZE;
0238:                        int valEnd = tlist.gapStart;
0239:                        char[] data = tlist.data;
0240:                        for (int i = valStart;;) {
0241:                            if (i >= valEnd) {
0242:                                // It's normalized.  Nothing to do.
0243:                                break;
0244:                            }
0245:                            char datum = data[i++];
0246:                            if (((datum & 0xFFFF) > TreeList.MAX_CHAR_SHORT)
0247:                                    || datum == '\t'
0248:                                    || datum == '\r'
0249:                                    || datum == '\n'
0250:                                    || (datum == ' ' && (i == valEnd || data[i] == ' '))) {
0251:                                // It's either not normalized, or the value contains
0252:                                // chars values above MAX_CHAR_SHORT or non-chars.
0253:                                // We could try to normalize in place but why bother?
0254:                                // I'm assuming xml:id are going be normalized already.
0255:                                // The exception is characters above MAX_CHAR_SHORT, but
0256:                                // let's defer that until TreeList gets re-written.
0257:                                StringBuffer sbuf = new StringBuffer();
0258:                                tlist.stringValue(valStart, valEnd, sbuf);
0259:                                tlist.gapStart = valStart;
0260:                                tlist.write(TextUtils.replaceWhitespace(sbuf
0261:                                        .toString(), true));
0262:                                break;
0263:                            }
0264:                        }
0265:                    }
0266:
0267:                    attrLocalName = null;
0268:                    attrPrefix = null;
0269:                    if (currentNamespacePrefix == null || namespacePrefixes)
0270:                        tlist.endAttribute();
0271:                    if (currentNamespacePrefix != null) {
0272:                        // Handle raw namespace attribute from parser.
0273:                        int attrStart = startIndexes[attrCount - 1];
0274:                        int uriStart = attrStart;
0275:                        int uriEnd = tlist.gapStart;
0276:                        int uriLength = uriEnd - uriStart;
0277:                        char[] data = tlist.data;
0278:
0279:                        // Check that the namespace attribute value is plain characters
0280:                        // so we an use the in-place buffer.
0281:                        // Calculate hash while we're at it.
0282:                        int uriHash = 0;
0283:                        for (int i = uriStart; i < uriEnd; i++) {
0284:                            char datum = data[i];
0285:                            if ((datum & 0xFFFF) > TreeList.MAX_CHAR_SHORT) {
0286:                                StringBuffer sbuf = new StringBuffer();
0287:                                tlist.stringValue(uriStart, uriEnd, sbuf);
0288:                                uriHash = sbuf.hashCode();
0289:                                uriStart = 0;
0290:                                uriEnd = uriLength = sbuf.length();
0291:                                data = new char[sbuf.length()];
0292:                                sbuf.getChars(0, uriEnd, data, 0);
0293:                                break;
0294:                            }
0295:                            uriHash = 31 * uriHash + datum;
0296:                        }
0297:                        tlist.gapStart = attrStart;
0298:
0299:                        String prefix = currentNamespacePrefix == "" ? null
0300:                                : currentNamespacePrefix;
0301:                        MappingInfo info = lookupNamespaceBinding(prefix, data,
0302:                                uriStart, uriLength, uriHash, namespaceBindings);
0303:                        namespaceBindings = info.namespaces;
0304:
0305:                        currentNamespacePrefix = null;
0306:                    }
0307:                }
0308:            }
0309:
0310:            private String resolve(String prefix, boolean isAttribute) {
0311:                if (isAttribute && prefix == null)
0312:                    return "";
0313:                String uri = namespaceBindings.resolve(prefix);
0314:                if (uri != null)
0315:                    return uri;
0316:                if (prefix != null)
0317:                    error('e', "unknown namespace prefix '" + prefix + '\'');
0318:                return "";
0319:            }
0320:
0321:            void closeStartTag() {
0322:                if (attrCount < 0 || stringizingLevel > 0)
0323:                    return;
0324:                inStartTag = false;
0325:                previous = 0;
0326:
0327:                if (attrLocalName != null) // Should only happen on erroneous input.
0328:                    endAttribute();
0329:                NamespaceBinding outer = nesting == 0 ? NamespaceBinding.predefinedXML
0330:                        : (NamespaceBinding) workStack[nesting - 2];
0331:
0332:                NamespaceBinding bindings = namespaceBindings;
0333:
0334:                // This first pass is to check that there are namespace declarations for
0335:                // each Symbol.
0336:                for (int i = 0; i <= attrCount; i++) {
0337:                    Object saved = workStack[nesting + i - 1];
0338:                    if (saved instanceof  Symbol) {
0339:                        Symbol sym = (Symbol) saved;
0340:                        String prefix = sym.getPrefix();
0341:                        if (prefix == "")
0342:                            prefix = null;
0343:                        String uri = sym.getNamespaceURI();
0344:                        if (uri == "")
0345:                            uri = null;
0346:                        if (i > 0 && prefix == null && uri == null)
0347:                            continue;
0348:                        boolean isOuter = false;
0349:                        for (NamespaceBinding ns = bindings;; ns = ns.next) {
0350:                            if (ns == outer)
0351:                                isOuter = true;
0352:                            if (ns == null) {
0353:                                if (prefix != null || uri != null)
0354:                                    bindings = findNamespaceBinding(prefix,
0355:                                            uri, bindings);
0356:                                break;
0357:                            }
0358:                            if (ns.prefix == prefix) {
0359:                                if (ns.uri != uri) {
0360:                                    if (isOuter)
0361:                                        bindings = findNamespaceBinding(prefix,
0362:                                                uri, bindings);
0363:                                    else {
0364:                                        // Try to find an alternative existing prefix:
0365:                                        String nprefix;
0366:                                        for (NamespaceBinding ns2 = bindings;; ns2 = ns2.next) {
0367:                                            if (ns2 == null) {
0368:                                                // We have to generate a new prefix.
0369:                                                for (int j = 1;; j++) {
0370:                                                    nprefix = ("_ns_" + j)
0371:                                                            .intern();
0372:                                                    if (bindings
0373:                                                            .resolve(nprefix) == null)
0374:                                                        break;
0375:                                                }
0376:                                                break;
0377:                                            }
0378:                                            if (ns2.uri == uri) {
0379:                                                nprefix = ns2.prefix;
0380:                                                if (bindings.resolve(nprefix) == uri)
0381:                                                    break;
0382:                                            }
0383:                                        }
0384:                                        bindings = findNamespaceBinding(
0385:                                                nprefix, uri, bindings);
0386:                                        String local = sym.getLocalName();
0387:                                        if (uri == null)
0388:                                            uri = "";
0389:                                        workStack[nesting + i - 1] = Symbol
0390:                                                .make(uri, local, nprefix);
0391:                                    }
0392:                                }
0393:                                break;
0394:                            }
0395:                        }
0396:                    }
0397:
0398:                }
0399:
0400:                for (int i = 0; i <= attrCount; i++) {
0401:                    Object saved = workStack[nesting + i - 1];
0402:                    MappingInfo info;
0403:                    boolean isNsNode = false;
0404:                    String prefix, uri, local;
0405:                    if (saved instanceof  MappingInfo || out == tlist) {
0406:                        if (saved instanceof  MappingInfo) {
0407:                            info = (MappingInfo) saved;
0408:                            prefix = info.prefix;
0409:                            local = info.local;
0410:                            if (i > 0
0411:                                    && ((prefix == null && local == "xmlns") || prefix == "xmlns")) {
0412:                                isNsNode = true;
0413:                                uri = "(namespace-node)";
0414:                            } else
0415:                                uri = resolve(prefix, i > 0);
0416:                        } else {
0417:                            Symbol symbol = (Symbol) saved;
0418:                            info = lookupTag(symbol);
0419:                            prefix = info.prefix;
0420:                            local = info.local;
0421:                            uri = symbol.getNamespaceURI();
0422:                        }
0423:                        int hash = info.tagHash;
0424:                        int bucket = hash & mappingTableMask;
0425:
0426:                        info = mappingTable[bucket];
0427:                        MappingInfo tagMatch = null;
0428:                        Object type;
0429:                        for (;; info = info.nextInBucket) {
0430:                            if (info == null) {
0431:                                info = tagMatch;
0432:                                info = new MappingInfo();
0433:                                info.tagHash = hash;
0434:                                info.prefix = prefix;
0435:                                info.local = local;
0436:                                info.nextInBucket = mappingTable[bucket];
0437:                                mappingTable[bucket] = info;
0438:                                info.uri = uri;
0439:                                info.qname = Symbol.make(uri, local, prefix);
0440:                                if (i == 0) {
0441:                                    XName xname = new XName(info.qname,
0442:                                            bindings);
0443:                                    type = xname;
0444:                                    info.type = xname;
0445:                                    info.namespaces = bindings;
0446:                                }
0447:                                break;
0448:                            }
0449:                            if (info.tagHash == hash && info.local == local
0450:                                    && info.prefix == prefix) {
0451:                                if (info.uri == null) {
0452:                                    info.uri = uri;
0453:                                    info.qname = Symbol
0454:                                            .make(uri, local, prefix);
0455:                                } else if (info.uri != uri)
0456:                                    continue;
0457:                                else if (info.qname == null)
0458:                                    info.qname = Symbol
0459:                                            .make(uri, local, prefix);
0460:                                if (i == 0) {
0461:                                    if (info.namespaces == bindings
0462:                                            || info.namespaces == null) {
0463:                                        type = info.type;
0464:                                        info.namespaces = bindings;
0465:                                        if (type == null) {
0466:                                            XName xname = new XName(info.qname,
0467:                                                    bindings);
0468:                                            type = xname;
0469:                                            info.type = xname;
0470:                                        }
0471:                                        break;
0472:                                    }
0473:                                } else {
0474:                                    type = info.qname;
0475:                                    break;
0476:                                }
0477:                            }
0478:                        }
0479:                        workStack[nesting + i - 1] = info;
0480:                    } else {
0481:                        Symbol sym = (Symbol) saved;
0482:                        uri = sym.getNamespaceURI();
0483:                        local = sym.getLocalName();
0484:                        info = null;
0485:                    }
0486:
0487:                    // Check for duplicated attribute names.
0488:                    for (int j = 1; j < i; j++) {
0489:                        Object other = workStack[nesting + j - 1];
0490:                        Symbol osym;
0491:                        if (other instanceof  Symbol)
0492:                            osym = (Symbol) other;
0493:                        else if (other instanceof  MappingInfo)
0494:                            osym = ((MappingInfo) other).qname;
0495:                        else
0496:                            continue;
0497:                        if (local == osym.getLocalPart()
0498:                                && uri == osym.getNamespaceURI()) {
0499:                            Object tag = workStack[nesting - 1];
0500:                            if (tag instanceof  MappingInfo)
0501:                                tag = ((MappingInfo) tag).qname;
0502:                            error('e', XMLFilter.duplicateAttributeMessage(
0503:                                    osym, tag));
0504:                        }
0505:                    }
0506:
0507:                    if (out == tlist) {
0508:                        Object type = i == 0 ? info.type : info.qname;
0509:                        int index = info.index;
0510:                        if (index <= 0 || tlist.objects[index] != type) {
0511:                            index = tlist.find(type);
0512:                            info.index = index;
0513:                        }
0514:                        if (i == 0)
0515:                            tlist.setElementName(tlist.gapEnd, index);
0516:                        else if (!isNsNode || namespacePrefixes)
0517:                            tlist.setAttributeName(startIndexes[i - 1], index);
0518:                    } else {
0519:                        Object type = info == null ? saved : i == 0 ? info.type
0520:                                : info.qname;
0521:                        if (i == 0)
0522:                            out.startElement(type);
0523:                        else if (!isNsNode || namespacePrefixes) {
0524:                            out.startAttribute(type);
0525:                            int start = startIndexes[i - 1];
0526:                            int end = i < attrCount ? startIndexes[i]
0527:                                    : tlist.gapStart;
0528:                            tlist.consumeIRange(start
0529:                                    + TreeList.BEGIN_ATTRIBUTE_LONG_SIZE, end
0530:                                    - TreeList.END_ATTRIBUTE_SIZE, out);
0531:                            out.endAttribute();
0532:                        }
0533:                    }
0534:                }
0535:
0536:                /* #ifdef SAX2 */
0537:                if (out instanceof  ContentConsumer)
0538:                    ((ContentConsumer) out).endStartTag();
0539:                /* #endif */
0540:
0541:                for (int i = 1; i <= attrCount; i++)
0542:                    workStack[nesting + i - 1] = null; // For GC.
0543:                if (out != tlist) {
0544:                    base = out;
0545:                    // Remove temporarily stored attributes.
0546:                    tlist.clear();
0547:                }
0548:                attrCount = -1;
0549:            }
0550:
0551:            protected boolean checkWriteAtomic() {
0552:                previous = 0;
0553:                if (ignoringLevel > 0)
0554:                    return false;
0555:                closeStartTag();
0556:                return true;
0557:            }
0558:
0559:            public void write(int v) {
0560:                if (checkWriteAtomic())
0561:                    base.write(v);
0562:            }
0563:
0564:            public void writeBoolean(boolean v) {
0565:                if (checkWriteAtomic())
0566:                    base.writeBoolean(v);
0567:            }
0568:
0569:            public void writeFloat(float v) {
0570:                if (checkWriteAtomic())
0571:                    base.writeFloat(v);
0572:            }
0573:
0574:            public void writeDouble(double v) {
0575:                if (checkWriteAtomic())
0576:                    base.writeDouble(v);
0577:            }
0578:
0579:            public void writeInt(int v) {
0580:                if (checkWriteAtomic())
0581:                    base.writeInt(v);
0582:            }
0583:
0584:            public void writeLong(long v) {
0585:                if (checkWriteAtomic())
0586:                    base.writeLong(v);
0587:            }
0588:
0589:            public void writeDocumentUri(Object uri) {
0590:                if (nesting == 2 && base instanceof  TreeList)
0591:                    ((TreeList) base).writeDocumentUri(uri);
0592:            }
0593:
0594:            public void consume(SeqPosition position) {
0595:                writePosition(position.sequence, position.ipos);
0596:            }
0597:
0598:            public void writePosition(AbstractSequence seq, int ipos) {
0599:                if (ignoringLevel > 0)
0600:                    return;
0601:                if (stringizingLevel > 0 && previous == SAW_WORD) {
0602:                    if (stringizingElementNesting < 0)
0603:                        write(' ');
0604:                    previous = 0;
0605:                }
0606:                seq.consumeNext(ipos, this );
0607:                if (stringizingLevel > 0 && stringizingElementNesting < 0)
0608:                    previous = SAW_WORD;
0609:            }
0610:
0611:            /** If v is a node, make a copy of it. */
0612:            public void writeObject(Object v) {
0613:                if (ignoringLevel > 0)
0614:                    return;
0615:                if (v instanceof  SeqPosition) {
0616:                    SeqPosition pos = (SeqPosition) v;
0617:                    writePosition(pos.sequence, pos.getPos());
0618:                } else if (v instanceof  TreeList)
0619:                    ((TreeList) v).consume(this );
0620:                else if (v instanceof  Keyword) {
0621:                    Keyword k = (Keyword) v;
0622:                    startAttribute(k.asSymbol());
0623:                    previous = SAW_KEYWORD;
0624:                } else {
0625:                    closeStartTag();
0626:                    if (v instanceof  UnescapedData) {
0627:                        base.writeObject(v);
0628:                        previous = 0;
0629:                    } else {
0630:                        if (previous == SAW_WORD)
0631:                            write(' ');
0632:                        TextUtils.textValue(v, this ); // Atomize.
0633:                        previous = SAW_WORD;
0634:                    }
0635:                }
0636:            }
0637:
0638:            public XMLFilter(Consumer out) {
0639:                this .base = out;
0640:                this .out = out;
0641:                if (out instanceof  NodeTree)
0642:                    this .tlist = (NodeTree) out;
0643:                else
0644:                    tlist = new TreeList(); // just for temporary storage
0645:
0646:                namespaceBindings = NamespaceBinding.predefinedXML;
0647:            }
0648:
0649:            /** Process raw text. */
0650:            public void write(char[] data, int start, int length) {
0651:                if (length == 0)
0652:                    writeJoiner();
0653:                else if (checkWriteAtomic())
0654:                    base.write(data, start, length);
0655:            }
0656:
0657:            public void write(String str) {
0658:                write(str, 0, str.length());
0659:            }
0660:
0661:            /* #ifdef use:java.lang.CharSequence */
0662:            public void write(CharSequence str, int start, int length)
0663:            /* #else */
0664:            // public void write(String str, int start, int length)
0665:            /* #endif */
0666:            {
0667:                if (length == 0)
0668:                    writeJoiner();
0669:                else if (checkWriteAtomic())
0670:                    base.write(str, start, length);
0671:            }
0672:
0673:            final boolean inElement() {
0674:                int i = nesting;
0675:                // Don't count nested document nodes.
0676:                while (i > 0 && workStack[i - 1] == null)
0677:                    i -= 2;
0678:                return i != 0;
0679:            }
0680:
0681:            public void linefeedFromParser() {
0682:                if (inElement() && checkWriteAtomic())
0683:                    base.write('\n');
0684:            }
0685:
0686:            public void textFromParser(char[] data, int start, int length) {
0687:                // We skip whitespace not in an element.
0688:                if (!inElement()) {
0689:                    for (int i = 0;; i++) {
0690:                        if (i == length)
0691:                            return;
0692:                        if (!Character.isWhitespace(data[start + i])) {
0693:                            error('e', "text at document level");
0694:                            break;
0695:                        }
0696:                    }
0697:                } else if (length > 0) {
0698:                    if (!checkWriteAtomic())
0699:                        return;
0700:
0701:                    base.write(data, start, length);
0702:                }
0703:            }
0704:
0705:            protected void writeJoiner() {
0706:                previous = 0;
0707:                if (ignoringLevel == 0)
0708:                    ((TreeList) base).writeJoiner();
0709:            }
0710:
0711:            /** Process a CDATA section.
0712:             * The data (starting at start for length char).
0713:             * Does not include the delimiters (i.e. {@code "<![CDATA["}
0714:             * and {@code "]]>"} are excluded). */
0715:            public void writeCDATA(char[] data, int start, int length) {
0716:                if (checkWriteAtomic()) {
0717:                    if (base instanceof  XConsumer)
0718:                        ((XConsumer) base).writeCDATA(data, start, length);
0719:                    else
0720:                        write(data, start, length);
0721:                }
0722:            }
0723:
0724:            protected void startElementCommon() {
0725:                closeStartTag();
0726:                if (stringizingLevel == 0) {
0727:                    ensureSpaceInWorkStack(nesting);
0728:                    workStack[nesting] = namespaceBindings;
0729:                    tlist.startElement(0);
0730:                    base = tlist;
0731:                    attrCount = 0;
0732:                } else {
0733:                    if (previous == SAW_WORD && stringizingElementNesting < 0)
0734:                        write(' ');
0735:                    previous = 0;
0736:                    if (stringizingElementNesting < 0)
0737:                        stringizingElementNesting = nesting;
0738:                }
0739:                nesting += 2;
0740:            }
0741:
0742:            /** Process a start tag, with the given element name. */
0743:            public void emitStartElement(char[] data, int start, int count) {
0744:                closeStartTag();
0745:                MappingInfo info = lookupTag(data, start, count);
0746:                startElementCommon();
0747:                ensureSpaceInWorkStack(nesting - 1);
0748:                workStack[nesting - 1] = info;
0749:            }
0750:
0751:            public void startElement(Object type) {
0752:                startElementCommon();
0753:                if (stringizingLevel == 0) {
0754:                    ensureSpaceInWorkStack(nesting - 1);
0755:                    workStack[nesting - 1] = type;
0756:                    if (copyNamespacesMode == 0)
0757:                        namespaceBindings = NamespaceBinding.predefinedXML;
0758:                    else if (copyNamespacesMode == COPY_NAMESPACES_PRESERVE
0759:                            || nesting == 2)
0760:                        namespaceBindings = (type instanceof  XName ? ((XName) type)
0761:                                .getNamespaceNodes()
0762:                                : NamespaceBinding.predefinedXML);
0763:                    else {
0764:                        NamespaceBinding inherited;
0765:                        // Start at 2, since workStack[0] just saves the predefinedXML.
0766:                        for (int i = 2;; i += 2) {
0767:                            if (i == nesting) {
0768:                                inherited = null;
0769:                                break;
0770:                            }
0771:                            if (workStack[i + 1] != null) { // Found an element, as opposed to a document.
0772:                                inherited = (NamespaceBinding) workStack[i];
0773:                                break;
0774:                            }
0775:                        }
0776:                        if (inherited == null) {
0777:                            // This is the outer-most element.
0778:                            namespaceBindings = (type instanceof  XName ? ((XName) type)
0779:                                    .getNamespaceNodes()
0780:                                    : NamespaceBinding.predefinedXML);
0781:                        } else if (copyNamespacesMode == COPY_NAMESPACES_INHERIT)
0782:                            namespaceBindings = inherited;
0783:                        else if (type instanceof  XName) {
0784:                            NamespaceBinding preserved = ((XName) type)
0785:                                    .getNamespaceNodes();
0786:                            NamespaceBinding join = NamespaceBinding
0787:                                    .commonAncestor(inherited, preserved);
0788:                            if (join == inherited)
0789:                                namespaceBindings = preserved;
0790:                            else
0791:                                namespaceBindings = mergeHelper(inherited,
0792:                                        preserved);
0793:                        } else
0794:                            namespaceBindings = inherited;
0795:                    }
0796:                }
0797:            }
0798:
0799:            private NamespaceBinding mergeHelper(NamespaceBinding list,
0800:                    NamespaceBinding node) {
0801:                if (node == NamespaceBinding.predefinedXML)
0802:                    return list;
0803:                list = mergeHelper(list, node.next);
0804:                String uri = node.uri;
0805:                if (list == null) {
0806:                    if (uri == null)
0807:                        return list;
0808:                    list = NamespaceBinding.predefinedXML;
0809:                }
0810:                String prefix = node.prefix;
0811:                String found = list.resolve(prefix);
0812:                if (found == null ? uri == null : found.equals(uri))
0813:                    return list;
0814:                return findNamespaceBinding(prefix, uri, list);
0815:            }
0816:
0817:            private boolean startAttributeCommon() {
0818:                if (stringizingElementNesting >= 0)
0819:                    ignoringLevel++;
0820:                if (stringizingLevel++ > 0)
0821:                    return false;
0822:
0823:                if (attrCount < 0) // A disembodied attribute.
0824:                    attrCount = 0;
0825:                ensureSpaceInWorkStack(nesting + attrCount);
0826:                ensureSpaceInStartIndexes(attrCount);
0827:                startIndexes[attrCount] = tlist.gapStart;
0828:                attrCount++;
0829:                return true;
0830:            }
0831:
0832:            public void startAttribute(Object attrType) {
0833:                previous = 0;
0834:                if (attrType instanceof  Symbol) {
0835:                    Symbol sym = (Symbol) attrType;
0836:                    String local = sym.getLocalPart();
0837:                    attrLocalName = local;
0838:                    attrPrefix = sym.getPrefix();
0839:                    String uri = sym.getNamespaceURI();
0840:                    if (uri == "http://www.w3.org/2000/xmlns/"
0841:                            || (uri == "" && local == "xmlns"))
0842:                        error('e',
0843:                                "arttribute name cannot be 'xmlns' or in xmlns namespace");
0844:                }
0845:                if (nesting == 2 && workStack[1] == null)
0846:                    error('e', "attribute not allowed at document level");
0847:                if (attrCount < 0 && nesting > 0)
0848:                    error('e', "attribute '" + attrType
0849:                            + "' follows non-attribute content");
0850:                if (!startAttributeCommon())
0851:                    return;
0852:                workStack[nesting + attrCount - 1] = attrType;
0853:                if (nesting == 0)
0854:                    base.startAttribute(attrType);
0855:                else
0856:                    tlist.startAttribute(0);
0857:            }
0858:
0859:            /** Process an attribute, with the given attribute name.
0860:             * The attribute value is given using {@code write}.
0861:             * The value is terminated by either another emitStartAttribute
0862:             * or an emitEndAttributes.
0863:             */
0864:            public void emitStartAttribute(char[] data, int start, int count) {
0865:                if (attrLocalName != null)
0866:                    endAttribute();
0867:                if (!startAttributeCommon())
0868:                    return;
0869:
0870:                MappingInfo info = lookupTag(data, start, count);
0871:                workStack[nesting + attrCount - 1] = info;
0872:                String prefix = info.prefix;
0873:                String local = info.local;
0874:                attrLocalName = local;
0875:                attrPrefix = prefix;
0876:                if (prefix != null) {
0877:                    if (prefix == "xmlns") {
0878:                        currentNamespacePrefix = local;
0879:                    }
0880:                } else {
0881:                    if (local == "xmlns" && prefix == null) {
0882:                        currentNamespacePrefix = "";
0883:                    }
0884:                }
0885:                if (currentNamespacePrefix == null || namespacePrefixes)
0886:                    tlist.startAttribute(0);
0887:            }
0888:
0889:            /** Process the end of a start tag.
0890:             * There are no more attributes. */
0891:            public void emitEndAttributes() {
0892:                if (attrLocalName != null)
0893:                    endAttribute();
0894:                closeStartTag();
0895:            }
0896:
0897:            /** Process an end tag.
0898:             * An abbreviated tag (such as {@code '<br/>'}) has a name==null.
0899:             */
0900:            public void emitEndElement(char[] data, int start, int length) {
0901:                if (attrLocalName != null) {
0902:                    error('e', "unclosed attribute"); // FIXME
0903:                    endAttribute();
0904:                }
0905:                if (!inElement()) {
0906:                    error('e', "unmatched end element"); // FIXME
0907:                    return;
0908:                }
0909:                if (data != null) {
0910:                    MappingInfo info = lookupTag(data, start, length);
0911:                    Object old = workStack[nesting - 1];
0912:                    if (old instanceof  MappingInfo && !mismatchReported) {
0913:                        MappingInfo mold = (MappingInfo) old;
0914:                        if (info.local != mold.local
0915:                                || info.prefix != mold.prefix) {
0916:                            StringBuffer sbuf = new StringBuffer("</");
0917:                            sbuf.append(data, start, length);
0918:                            sbuf.append("> matching <");
0919:                            String oldPrefix = mold.prefix;
0920:                            if (oldPrefix != null) {
0921:                                sbuf.append(oldPrefix);
0922:                                sbuf.append(':');
0923:                            }
0924:                            sbuf.append(mold.local);
0925:                            sbuf.append('>');
0926:                            error('e', sbuf.toString());
0927:                            mismatchReported = true;
0928:                        }
0929:                    }
0930:                }
0931:                closeStartTag();
0932:                if (nesting <= 0)
0933:                    return; // Only if error.
0934:                endElement();
0935:            }
0936:
0937:            public void endElement() {
0938:                closeStartTag();
0939:                nesting -= 2;
0940:                previous = 0;
0941:                if (stringizingLevel == 0) {
0942:                    namespaceBindings = (NamespaceBinding) workStack[nesting];
0943:                    workStack[nesting] = null;
0944:                    workStack[nesting + 1] = null;
0945:                    base.endElement();
0946:                } else if (stringizingElementNesting == nesting) {
0947:                    stringizingElementNesting = -1;
0948:                    previous = SAW_WORD;
0949:                }
0950:                /*
0951:                if (nesting == 0)
0952:                  {
0953:                    workStack = null;
0954:                    attrIndexes = null;
0955:                  }
0956:                 */
0957:            }
0958:
0959:            /** Process an entity reference.
0960:             * The entity name is given.
0961:             * This handles the predefined entities, such as "&lt;" and "&quot;".
0962:             */
0963:            public void emitEntityReference(char[] name, int start, int length) {
0964:                char c0 = name[start];
0965:                char ch = '?';
0966:                if (length == 2 && name[start + 1] == 't') {
0967:
0968:                    if (c0 == 'l')
0969:                        ch = '<';
0970:                    else if (c0 == 'g')
0971:                        ch = '>';
0972:                } else if (length == 3) {
0973:                    if (c0 == 'a' && name[start + 1] == 'm'
0974:                            && name[start + 2] == 'p')
0975:                        ch = '&';
0976:                } else if (length == 4) {
0977:                    char c1 = name[start + 1];
0978:                    char c2 = name[start + 2];
0979:                    char c3 = name[start + 3];
0980:                    if (c0 == 'q' && c1 == 'u' && c2 == 'o' && c3 == 't')
0981:                        ch = '"';
0982:                    else if (c0 == 'a' && c1 == 'p' && c2 == 'o' && c3 == 's')
0983:                        ch = '\'';
0984:                }
0985:                write(ch);
0986:            }
0987:
0988:            /** Process a character entity reference.
0989:             * The string encoding of the character (e.g. "xFF" or "255") is given,
0990:             * as well as the character value. */
0991:            public void emitCharacterReference(int value, char[] name,
0992:                    int start, int length) {
0993:                if (value >= 0x10000)
0994:                    Char.print(value, this );
0995:                else
0996:                    write(value);
0997:            }
0998:
0999:            protected void checkValidComment(char[] chars, int offset,
1000:                    int length) {
1001:                int i = length;
1002:                boolean sawHyphen = true;
1003:                while (--i >= 0) {
1004:                    boolean curHyphen = chars[offset + i] == '-';
1005:                    if (sawHyphen && curHyphen) {
1006:                        error('e', "consecutive or final hyphen in XML comment");
1007:                        break;
1008:                    }
1009:                    sawHyphen = curHyphen;
1010:                }
1011:            }
1012:
1013:            /** Process a comment.
1014:             * The data (starting at start for length chars).
1015:             * Does not include the delimiters (i.e. "<!--" and "-->" are excluded). */
1016:            public void writeComment(char[] chars, int start, int length) {
1017:                checkValidComment(chars, start, length);
1018:                commentFromParser(chars, start, length);
1019:            }
1020:
1021:            /** Process a comment, when called from an XML parser.
1022:             * The data (starting at start for length chars).
1023:             * Does not include the delimiters (i.e. "<!--" and "-->" are excluded). */
1024:            public void commentFromParser(char[] chars, int start, int length) {
1025:                if (stringizingLevel == 0) {
1026:                    closeStartTag();
1027:                    if (base instanceof  XConsumer)
1028:                        ((XConsumer) base).writeComment(chars, start, length);
1029:                } else if (stringizingElementNesting < 0)
1030:                    base.write(chars, start, length);
1031:            }
1032:
1033:            public void writeProcessingInstruction(String target,
1034:                    char[] content, int offset, int length) {
1035:                target = TextUtils.replaceWhitespace(target, true);
1036:                for (int i = offset + length; --i >= offset;) {
1037:                    char ch = content[i];
1038:                    while (ch == '>' && --i >= offset) {
1039:                        ch = content[i];
1040:                        if (ch == '?') {
1041:                            error('e',
1042:                                    "'?>' is not allowed in a processing-instruction");
1043:                            break;
1044:                        }
1045:                    }
1046:                }
1047:
1048:                if ("xml".equalsIgnoreCase(target))
1049:                    error('e',
1050:                            "processing-instruction target may not be 'xml' (ignoring case)");
1051:                if (!XName.isNCName(target))
1052:                    error('e', "processing-instruction target '" + target
1053:                            + "' is not a valid Name");
1054:
1055:                processingInstructionCommon(target, content, offset, length);
1056:            }
1057:
1058:            void processingInstructionCommon(String target, char[] content,
1059:                    int offset, int length) {
1060:                if (stringizingLevel == 0) {
1061:                    closeStartTag();
1062:                    if (base instanceof  XConsumer)
1063:                        ((XConsumer) base).writeProcessingInstruction(target,
1064:                                content, offset, length);
1065:                } else if (stringizingElementNesting < 0)
1066:                    base.write(content, offset, length);
1067:            }
1068:
1069:            /** Process a processing instruction. */
1070:            public void processingInstructionFromParser(char[] buffer,
1071:                    int tstart, int tlength, int dstart, int dlength) {
1072:                // Skip XML declaration.
1073:                if (tlength == 3 && !inElement() && buffer[tstart] == 'x'
1074:                        && buffer[tstart + 1] == 'm'
1075:                        && buffer[tstart + 2] == 'l')
1076:                    return;
1077:                String target = new String(buffer, tstart, tlength);
1078:                processingInstructionCommon(target, buffer, dstart, dlength);
1079:            }
1080:
1081:            public void startDocument() {
1082:                closeStartTag();
1083:                if (stringizingLevel > 0)
1084:                    writeJoiner();
1085:                // We need to increment nesting so that endDocument can decrement it.
1086:                else {
1087:                    if (nesting == 0)
1088:                        base.startDocument();
1089:                    else
1090:                        writeJoiner();
1091:                    ensureSpaceInWorkStack(nesting);
1092:                    workStack[nesting] = namespaceBindings;
1093:                    // The following should be redundant, but just in case ...
1094:                    // Having workStack[nesting+1] be null identifies that nesting
1095:                    // level as being a document rather than an element.
1096:                    workStack[nesting + 1] = null;
1097:                    nesting += 2;
1098:                }
1099:            }
1100:
1101:            public void endDocument() {
1102:                if (stringizingLevel > 0) {
1103:                    writeJoiner();
1104:                    return;
1105:                }
1106:                nesting -= 2;
1107:                namespaceBindings = (NamespaceBinding) workStack[nesting];
1108:                workStack[nesting] = null;
1109:                workStack[nesting + 1] = null;
1110:                if (nesting == 0)
1111:                    base.endDocument();
1112:                else
1113:                    writeJoiner();
1114:                /*
1115:                if (nesting == 0)
1116:                  {
1117:                    workStack = null;
1118:                    attrIndexes = null;
1119:                  }
1120:                 */
1121:            }
1122:
1123:            /** Process a DOCTYPE declaration. */
1124:            public void emitDoctypeDecl(char[] buffer, int target, int tlength,
1125:                    int data, int dlength) {
1126:                // FIXME?
1127:            }
1128:
1129:            public void beginEntity(Object baseUri) {
1130:                if (base instanceof  XConsumer)
1131:                    ((XConsumer) base).beginEntity(baseUri);
1132:            }
1133:
1134:            public void endEntity() {
1135:                if (base instanceof  XConsumer)
1136:                    ((XConsumer) base).endEntity();
1137:            }
1138:
1139:            /* #ifdef JAVA5 */
1140:            // public XMLFilter append (char c)
1141:            // {
1142:            //   write(c);
1143:            //   return this;
1144:            // }
1145:            // public XMLFilter append (CharSequence csq)
1146:            // {
1147:            //   if (csq == null)
1148:            //     csq = "null";
1149:            //   append(csq, 0, csq.length());
1150:            //   return this;
1151:            // }
1152:            // public XMLFilter append (CharSequence csq, int start, int end)
1153:            // {
1154:            //   if (csq == null)
1155:            //     csq = "null";
1156:            //   write(csq, start, end-start);
1157:            //   return this;
1158:            // }
1159:            /* #endif */
1160:
1161:            MappingInfo lookupTag(Symbol qname) {
1162:                String local = qname.getLocalPart();
1163:                String prefix = qname.getPrefix();
1164:                if (prefix == "")
1165:                    prefix = null;
1166:                String uri = qname.getNamespaceURI();
1167:                int hash = MappingInfo.hash(prefix, local);
1168:                int index = hash & mappingTableMask;
1169:                MappingInfo first = mappingTable[index];
1170:                MappingInfo info = first;
1171:                for (;;) {
1172:                    if (info == null) {
1173:                        // No match found - create a new MappingInfo and Strings.
1174:                        info = new MappingInfo();
1175:                        info.qname = qname;
1176:                        info.prefix = prefix;
1177:                        info.uri = uri;
1178:                        info.local = local;
1179:                        info.tagHash = hash;
1180:                        info.nextInBucket = first;
1181:                        mappingTable[index] = first;
1182:                        return info;
1183:                    }
1184:                    if (qname == info.qname)
1185:                        return info;
1186:                    if (local == info.local && info.qname == null
1187:                            && (uri == info.uri || info.uri == null)
1188:                            && prefix == info.prefix) {
1189:                        info.uri = uri;
1190:                        info.qname = qname;
1191:                        return info;
1192:                    }
1193:                    info = info.nextInBucket;
1194:                }
1195:            }
1196:
1197:            /** Look up an attribute/element tag (a QName as a lexical string
1198:             * before namespace resolution), and return a MappingInfo with the
1199:             * tagHash, prefix, and local fields set.
1200:             * The trick is to avoid allocating a new String for each element or
1201:             * attribute node we see, but only allocate a new String when we see a
1202:             * tag we haven't seen.  So we calculate the hash code using the
1203:             * characters in the array, rather than using String's hashCode.
1204:             */
1205:            MappingInfo lookupTag(char[] data, int start, int length) {
1206:                // Calculate hash code.  Also note presence+position of ':'.
1207:                int hash = 0;
1208:                int prefixHash = 0;
1209:                int colon = -1;
1210:                for (int i = 0; i < length; i++) {
1211:                    char ch = data[start + i];
1212:                    if (ch == ':' && colon < 0) {
1213:                        colon = i;
1214:                        prefixHash = hash;
1215:                        hash = 0;
1216:                    } else
1217:                        hash = 31 * hash + ch;
1218:                }
1219:                hash = prefixHash ^ hash;
1220:                int index = hash & mappingTableMask;
1221:                MappingInfo first = mappingTable[index];
1222:                MappingInfo info = first;
1223:                for (;;) {
1224:                    if (info == null) {
1225:                        // No match found - create a new MappingInfo and Strings.
1226:                        info = new MappingInfo();
1227:                        info.tagHash = hash;
1228:                        if (colon >= 0) {
1229:                            info.prefix = new String(data, start, colon)
1230:                                    .intern();
1231:                            colon++;
1232:                            int lstart = start + colon;
1233:                            info.local = new String(data, lstart, length
1234:                                    - colon).intern();
1235:                        } else {
1236:                            info.prefix = null;
1237:                            info.local = new String(data, start, length)
1238:                                    .intern();
1239:                        }
1240:                        info.nextInBucket = first;
1241:                        mappingTable[index] = first;
1242:                        return info;
1243:                    }
1244:                    if (hash == info.tagHash && info.match(data, start, length))
1245:                        return info;
1246:                    info = info.nextInBucket;
1247:                }
1248:            }
1249:
1250:            private void ensureSpaceInWorkStack(int oldSize) {
1251:                if (workStack == null) {
1252:                    workStack = new Object[20];
1253:                } else if (oldSize >= workStack.length) {
1254:                    Object[] tmpn = new Object[2 * workStack.length];
1255:                    System.arraycopy(workStack, 0, tmpn, 0, oldSize);
1256:                    workStack = tmpn;
1257:                }
1258:            }
1259:
1260:            private void ensureSpaceInStartIndexes(int oldSize) {
1261:                if (startIndexes == null) {
1262:                    startIndexes = new int[20];
1263:                } else if (oldSize >= startIndexes.length) {
1264:                    int[] tmpn = new int[2 * startIndexes.length];
1265:                    System.arraycopy(startIndexes, 0, tmpn, 0, oldSize);
1266:                    startIndexes = tmpn;
1267:                }
1268:            }
1269:
1270:            public static String duplicateAttributeMessage(Symbol attrSymbol,
1271:                    Object elementName) {
1272:                StringBuffer sbuf = new StringBuffer("duplicate attribute: ");
1273:                String uri = attrSymbol.getNamespaceURI();
1274:                if (uri != null && uri.length() > 0) {
1275:                    sbuf.append('{');
1276:                    sbuf.append('}');
1277:                    sbuf.append(uri);
1278:                }
1279:                sbuf.append(attrSymbol.getLocalPart());
1280:                if (elementName != null) {
1281:                    sbuf.append(" in <");
1282:                    sbuf.append(elementName);
1283:                    sbuf.append('>');
1284:                }
1285:                return sbuf.toString();
1286:            }
1287:
1288:            public void error(char severity, String message) {
1289:                if (messages == null)
1290:                    throw new RuntimeException(message);
1291:                else if (locator != null)
1292:                    messages.error(severity, locator, message);
1293:                else
1294:                    messages.error(severity, message);
1295:            }
1296:
1297:            public boolean ignoring() {
1298:                return ignoringLevel > 0;
1299:            }
1300:
1301:            /* #ifdef SAX2 */
1302:            public void setDocumentLocator(Locator locator) {
1303:                if (locator instanceof  SourceLocator)
1304:                    this .locator = (SourceLocator) locator;
1305:                else
1306:                    ; // create SourceLocator that indirects to given locator.  FIXME.
1307:            }
1308:
1309:            public void startElement(String namespaceURI, String localName,
1310:                    String qName, Attributes atts) {
1311:                startElement(Symbol.make(namespaceURI, localName));
1312:                int numAttributes = atts.getLength();
1313:                for (int i = 0; i < numAttributes; i++) {
1314:                    startAttribute(Symbol.make(atts.getURI(i), atts
1315:                            .getLocalName(i)));
1316:                    write(atts.getValue(i));
1317:                    endAttribute();
1318:                }
1319:            }
1320:
1321:            public void endElement(String namespaceURI, String localName,
1322:                    String qName) {
1323:                endElement();
1324:            }
1325:
1326:            public void startElement(String name, AttributeList atts) {
1327:                name = name.intern(); // ???
1328:                startElement(name); // FIXME
1329:                int attrLength = atts.getLength();
1330:                for (int i = 0; i < attrLength; i++) {
1331:                    name = atts.getName(i);
1332:                    name = name.intern(); // ?
1333:                    String type = atts.getType(i);
1334:                    String value = atts.getValue(i);
1335:                    startAttribute(name); // FIXME
1336:                    write(value);
1337:                    endAttribute();
1338:                }
1339:            }
1340:
1341:            public void endElement(String name) throws SAXException {
1342:                endElement();
1343:            }
1344:
1345:            public void characters(char ch[], int start, int length)
1346:                    throws SAXException {
1347:                write(ch, start, length);
1348:            }
1349:
1350:            public void ignorableWhitespace(char ch[], int start, int length)
1351:                    throws SAXException {
1352:                write(ch, start, length); // FIXME
1353:            }
1354:
1355:            /* #endif */
1356:
1357:            public void processingInstruction(String target, String data) {
1358:                // FIXME - this could be done more efficiently by copying the
1359:                // string into tlist.
1360:                char[] chars = data.toCharArray();
1361:                processingInstructionCommon(target, chars, 0, chars.length);
1362:            }
1363:
1364:            public void startPrefixMapping(String prefix, String uri) {
1365:                namespaceBindings = findNamespaceBinding(prefix.intern(), uri
1366:                        .intern(), namespaceBindings);
1367:            }
1368:
1369:            public void endPrefixMapping(String prefix) {
1370:                namespaceBindings = namespaceBindings.getNext();
1371:            }
1372:
1373:            public void skippedEntity(String name) {
1374:                // FIXME
1375:            }
1376:
1377:            public String getPublicId() {
1378:                return null;
1379:            }
1380:
1381:            public String getSystemId() {
1382:                return in == null ? null : in.getName();
1383:            }
1384:
1385:            public String getFileName() {
1386:                return in == null ? null : in.getName();
1387:            }
1388:
1389:            public int getLineNumber() {
1390:                if (in == null)
1391:                    return -1;
1392:                int line = in.getLineNumber();
1393:                return line < 0 ? -1 : line + 1;
1394:            }
1395:
1396:            public int getColumnNumber() {
1397:                int col;
1398:                return in != null && (col = in.getColumnNumber()) > 0 ? col
1399:                        : -1;
1400:            }
1401:
1402:            public boolean isStableSourceLocation() {
1403:                return false;
1404:            }
1405:        }
1406:
1407:        final class MappingInfo {
1408:            /** Next in same hash bucket. */
1409:            MappingInfo nextInBucket;
1410:
1411:            // maybe future: MappingInfo prevInBucket;
1412:            // maybe future: MappingInfo nextForPrefix;
1413:
1414:            /** The cached value of {@code hash(prefix, local)}. */
1415:            int tagHash;
1416:
1417:            /** The prefix part of tag: - the part before the colon.
1418:             * It is null if there is no colon in tag.  Otherwise it is interned.  */
1419:            String prefix;
1420:
1421:            /** The local name part of tag: - the part after the colon. 
1422:             * It is interned.  */
1423:            String local;
1424:
1425:            /** The namespace URI.
1426:             * The value null means "unknown". */
1427:            String uri;
1428:
1429:            /** The Symbol for the resolved QName.
1430:             * If non-null, it must be the case that {@code uri!= null}, and
1431:             * {@code qname==Symbol.make(uri, local, prefix==null?"":prefix)}.
1432:             */
1433:            Symbol qname;
1434:
1435:            NamespaceBinding namespaces;
1436:
1437:            /** An XName matching the other fields.
1438:             * If non-null, we must have {@code qname!=null}, {@code namespaces!=null},
1439:             * {@code type.namespaceNodes == namespaces}, and
1440:             * {@code type.equals(qname)}. */
1441:            XName type;
1442:
1443:            /** If non-negative: An index into a TreeList objects array. */
1444:            int index = -1;
1445:
1446:            static int hash(String prefix, String local) {
1447:                int hash = local.hashCode();
1448:                if (prefix != null)
1449:                    hash ^= prefix.hashCode();
1450:                return hash;
1451:            }
1452:
1453:            /** Hash a QName, handling an optional prefix+colon. */
1454:            static int hash(char[] data, int start, int length) {
1455:                int hash = 0;
1456:                int prefixHash = 0;
1457:                int colonPos = -1;
1458:                for (int i = 0; i < length; i++) {
1459:                    char ch = data[start + i];
1460:                    if (ch == ':' && colonPos < 0) {
1461:                        colonPos = i;
1462:                        prefixHash = hash;
1463:                        hash = 0;
1464:                    } else
1465:                        hash = 31 * hash + ch;
1466:                }
1467:                return prefixHash ^ hash;
1468:            }
1469:
1470:            /** Match {@code "[prefix:]length"} against {@code new String(data, start, next)}. */
1471:            boolean match(char[] data, int start, int length) {
1472:                if (prefix != null) {
1473:                    int localLength = local.length();
1474:                    int prefixLength = prefix.length();
1475:                    return length == prefixLength + 1 + localLength
1476:                            && data[prefixLength] == ':'
1477:                            && equals(prefix, data, start, prefixLength)
1478:                            && equals(local, data, start + prefixLength + 1,
1479:                                    localLength);
1480:                } else
1481:                    return equals(local, data, start, length);
1482:            }
1483:
1484:            /** An optimization of {@code sbuf.toString().equals(tag)}.
1485:             */
1486:            static boolean equals(String tag, StringBuffer sbuf) {
1487:                int length = sbuf.length();
1488:                if (tag.length() != length)
1489:                    return false;
1490:                for (int i = 0; i < length; i++)
1491:                    if (sbuf.charAt(i) != tag.charAt(i))
1492:                        return false;
1493:                return true;
1494:            }
1495:
1496:            static boolean equals(String tag, char[] data, int start, int length) {
1497:                if (tag.length() != length)
1498:                    return false;
1499:                for (int i = 0; i < length; i++)
1500:                    if (data[start + i] != tag.charAt(i))
1501:                        return false;
1502:                return true;
1503:            }
1504:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.