Source Code Cross Referenced for NodeWrapper.java in  » XML » saxonb » net » sf » saxon » dom » 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 » XML » saxonb » net.sf.saxon.dom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package net.sf.saxon.dom;
0002:
0003:        import net.sf.saxon.Configuration;
0004:        import net.sf.saxon.event.Receiver;
0005:        import net.sf.saxon.om.*;
0006:        import net.sf.saxon.pattern.NameTest;
0007:        import net.sf.saxon.pattern.NodeTest;
0008:        import net.sf.saxon.style.StandardNames;
0009:        import net.sf.saxon.trans.XPathException;
0010:        import net.sf.saxon.type.Type;
0011:        import net.sf.saxon.value.UntypedAtomicValue;
0012:        import net.sf.saxon.value.Value;
0013:        import org.w3c.dom.*;
0014:
0015:        import java.lang.reflect.InvocationTargetException;
0016:        import java.lang.reflect.Method;
0017:        import java.util.ArrayList;
0018:
0019:        /**
0020:         * A node in the XML parse tree representing an XML element, character content, or attribute.<P>
0021:         * This is the implementation of the NodeInfo interface used as a wrapper for DOM nodes.
0022:         */
0023:
0024:        public class NodeWrapper implements  NodeInfo, VirtualNode,
0025:                SiblingCountingNode {
0026:
0027:            protected Node node;
0028:            private int namecode = -1;
0029:            protected short nodeKind;
0030:            private NodeWrapper parent; // null means unknown
0031:            protected DocumentWrapper docWrapper;
0032:            protected int index; // -1 means unknown
0033:            protected int span = 1; // the number of adjacent text nodes wrapped by this NodeWrapper.
0034:
0035:            // If span>1, node will always be the first of a sequence of adjacent text nodes
0036:
0037:            /**
0038:             * This constructor is protected: nodes should be created using the makeWrapper
0039:             * factory method
0040:             * @param node    The DOM node to be wrapped
0041:             * @param parent  The NodeWrapper that wraps the parent of this node
0042:             * @param index   Position of this node among its siblings
0043:             */
0044:            protected NodeWrapper(Node node, NodeWrapper parent, int index) {
0045:                this .node = node;
0046:                this .parent = parent;
0047:                this .index = index;
0048:            }
0049:
0050:            /**
0051:             * Factory method to wrap a DOM node with a wrapper that implements the Saxon
0052:             * NodeInfo interface.
0053:             * @param node        The DOM node
0054:             * @param docWrapper  The wrapper for the containing Document node
0055:             * @return            The new wrapper for the supplied node
0056:             * @throws NullPointerException if the node or the document wrapper are null
0057:             */
0058:            protected NodeWrapper makeWrapper(Node node,
0059:                    DocumentWrapper docWrapper) {
0060:                if (node == null) {
0061:                    throw new NullPointerException(
0062:                            "NodeWrapper#makeWrapper: Node must not be null");
0063:                }
0064:                if (docWrapper == null) {
0065:                    throw new NullPointerException(
0066:                            "NodeWrapper#makeWrapper: DocumentWrapper must not be null");
0067:                }
0068:                return makeWrapper(node, docWrapper, null, -1);
0069:            }
0070:
0071:            /**
0072:             * Factory method to wrap a DOM node with a wrapper that implements the Saxon
0073:             * NodeInfo interface.
0074:             * @param node        The DOM node
0075:             * @param docWrapper  The wrapper for the containing Document node     *
0076:             * @param parent      The wrapper for the parent of the JDOM node
0077:             * @param index       The position of this node relative to its siblings
0078:             * @return            The new wrapper for the supplied node
0079:             */
0080:
0081:            protected NodeWrapper makeWrapper(Node node,
0082:                    DocumentWrapper docWrapper, NodeWrapper parent, int index) {
0083:                NodeWrapper wrapper;
0084:                switch (node.getNodeType()) {
0085:                case Node.DOCUMENT_NODE:
0086:                    return docWrapper;
0087:                case Node.ELEMENT_NODE:
0088:                    wrapper = new NodeWrapper(node, parent, index);
0089:                    wrapper.nodeKind = Type.ELEMENT;
0090:                    break;
0091:                case Node.ATTRIBUTE_NODE:
0092:                    wrapper = new NodeWrapper(node, parent, index);
0093:                    wrapper.nodeKind = Type.ATTRIBUTE;
0094:                    break;
0095:                case Node.TEXT_NODE:
0096:                    wrapper = new NodeWrapper(node, parent, index);
0097:                    wrapper.nodeKind = Type.TEXT;
0098:                    break;
0099:                case Node.CDATA_SECTION_NODE:
0100:                    wrapper = new NodeWrapper(node, parent, index);
0101:                    wrapper.nodeKind = Type.TEXT;
0102:                    break;
0103:                case Node.COMMENT_NODE:
0104:                    wrapper = new NodeWrapper(node, parent, index);
0105:                    wrapper.nodeKind = Type.COMMENT;
0106:                    break;
0107:                case Node.PROCESSING_INSTRUCTION_NODE:
0108:                    wrapper = new NodeWrapper(node, parent, index);
0109:                    wrapper.nodeKind = Type.PROCESSING_INSTRUCTION;
0110:                    break;
0111:                default:
0112:                    throw new IllegalArgumentException(
0113:                            "Unsupported node type in DOM! "
0114:                                    + node.getNodeType() + " instance "
0115:                                    + node.toString());
0116:                }
0117:                wrapper.docWrapper = docWrapper;
0118:                return wrapper;
0119:            }
0120:
0121:            /**
0122:             * Get the underlying DOM node, to implement the VirtualNode interface
0123:             */
0124:
0125:            public Object getUnderlyingNode() {
0126:                return node;
0127:            }
0128:
0129:            /**
0130:             * Get the configuration
0131:             */
0132:
0133:            public Configuration getConfiguration() {
0134:                return docWrapper.getConfiguration();
0135:            }
0136:
0137:            /**
0138:             * Get the name pool for this node
0139:             * @return the NamePool
0140:             */
0141:
0142:            public NamePool getNamePool() {
0143:                return docWrapper.getNamePool();
0144:            }
0145:
0146:            /**
0147:             * Return the type of node.
0148:             * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc.
0149:             */
0150:
0151:            public int getNodeKind() {
0152:                return nodeKind;
0153:            }
0154:
0155:            /**
0156:             * Get the typed value of the item
0157:             */
0158:
0159:            public SequenceIterator getTypedValue() {
0160:                return SingletonIterator.makeIterator(new UntypedAtomicValue(
0161:                        getStringValueCS()));
0162:            }
0163:
0164:            /**
0165:             * Get the typed value. The result of this method will always be consistent with the method
0166:             * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be
0167:             * more efficient, especially in the common case where the value is expected to be a singleton.
0168:             *
0169:             * @return the typed value. If requireSingleton is set to true, the result will always be an
0170:             *         AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
0171:             *         values.
0172:             * @since 8.5
0173:             */
0174:
0175:            public Value atomize() throws XPathException {
0176:                return new UntypedAtomicValue(getStringValueCS());
0177:            }
0178:
0179:            /**
0180:             * Get the type annotation
0181:             * @return -1 (there is no type annotation)
0182:             */
0183:
0184:            public int getTypeAnnotation() {
0185:                return -1;
0186:            }
0187:
0188:            /**
0189:             * Determine whether this is the same node as another node. <br />
0190:             * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b)
0191:             * @return true if this Node object and the supplied Node object represent the
0192:             * same node in the tree.
0193:             */
0194:
0195:            public boolean isSameNodeInfo(NodeInfo other) {
0196:                // DOM does not offer any guarantees that the same node is always represented
0197:                // by the same object
0198:
0199:                if (!(other instanceof  NodeWrapper)) {
0200:                    return false;
0201:                }
0202:
0203:                // For a level-3 DOM, use the DOM isSameNode() method
0204:                if (docWrapper.level3) {
0205:                    try {
0206:                        Class[] argClasses = { Node.class };
0207:                        Method isSameNode = Node.class.getMethod("isSameNode",
0208:                                argClasses);
0209:                        Object[] args = { ((NodeWrapper) other).node };
0210:                        Boolean b = (Boolean) (isSameNode.invoke(node, args));
0211:                        return b.booleanValue();
0212:                    } catch (NoSuchMethodException e) {
0213:                        // use fallback implementation
0214:                    } catch (IllegalAccessException e) {
0215:                        // use fallback implementation
0216:                    } catch (InvocationTargetException e) {
0217:                        // use fallback implementation
0218:                    }
0219:                }
0220:                NodeWrapper ow = (NodeWrapper) other;
0221:                return getNodeKind() == ow.getNodeKind()
0222:                        && getNameCode() == ow.getNameCode()
0223:                        && // redundant, but gives a quick exit
0224:                        getSiblingPosition() == ow.getSiblingPosition()
0225:                        && getParent().isSameNodeInfo(ow.getParent());
0226:                // Note: this has been known to fail because getParent() returns null. Extra checks have been added to the
0227:                // methods for constructing DOM document wrappers to ensure that wrapped nodes always belong to a wrapped
0228:                // Document, which should prevent this happening again.
0229:            }
0230:
0231:            /**
0232:             * Get the System ID for the node.
0233:             * @return the System Identifier of the entity in the source document containing the node,
0234:             * or null if not known. Note this is not the same as the base URI: the base URI can be
0235:             * modified by xml:base, but the system ID cannot.
0236:             */
0237:
0238:            public String getSystemId() {
0239:                return docWrapper.baseURI;
0240:            }
0241:
0242:            public void setSystemId(String uri) {
0243:                docWrapper.baseURI = uri;
0244:            }
0245:
0246:            /**
0247:             * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
0248:             * in the node. In the DOM model, base URIs are held only an the document level.
0249:             */
0250:
0251:            public String getBaseURI() {
0252:                NodeInfo n = this ;
0253:                if (getNodeKind() != Type.ELEMENT) {
0254:                    n = getParent();
0255:                }
0256:                // Look for an xml:base attribute
0257:                while (n != null) {
0258:                    String xmlbase = n
0259:                            .getAttributeValue(StandardNames.XML_BASE);
0260:                    if (xmlbase != null) {
0261:                        return xmlbase;
0262:                    }
0263:                    n = n.getParent();
0264:                }
0265:                // if not found, return the base URI of the document node
0266:                return docWrapper.baseURI;
0267:            }
0268:
0269:            /**
0270:             * Get line number
0271:             * @return the line number of the node in its original source document; or -1 if not available
0272:             */
0273:
0274:            public int getLineNumber() {
0275:                return -1;
0276:            }
0277:
0278:            /**
0279:             * Determine the relative position of this node and another node, in document order.
0280:             * The other node will always be in the same document.
0281:             * @param other The other node, whose position is to be compared with this node
0282:             * @return -1 if this node precedes the other node, +1 if it follows the other
0283:             * node, or 0 if they are the same node. (In this case, isSameNode() will always
0284:             * return true, and the two nodes will produce the same result for generateId())
0285:             */
0286:
0287:            public int compareOrder(NodeInfo other) {
0288:                // Use the DOM Level-3 compareDocumentPosition() method if available
0289:                if (docWrapper.level3 && other instanceof  NodeWrapper) {
0290:                    if (isSameNodeInfo(other)) {
0291:                        return 0;
0292:                    }
0293:                    try {
0294:                        Class[] argClasses = { Node.class };
0295:                        Method compareDocumentPosition = Node.class.getMethod(
0296:                                "compareDocumentPosition", argClasses);
0297:                        Object[] args = { ((NodeWrapper) other).node };
0298:                        Short i = (Short) (compareDocumentPosition.invoke(node,
0299:                                args));
0300:                        switch (i.shortValue()) {
0301:                        // the symbolic constants require JDK 1.5
0302:                        case 2: //Node.DOCUMENT_POSITION_PRECEDING:
0303:                        case 8: //Node.DOCUMENT_POSITION_CONTAINS:
0304:                            return +1;
0305:                        case 4: //Node.DOCUMENT_POSITION_FOLLOWING:
0306:                        case 16: //Node.DOCUMENT_POSITION_CONTAINED_BY:
0307:                            return -1;
0308:                        default:
0309:                            // use fallback implementation
0310:                        }
0311:                    } catch (NoSuchMethodException e) {
0312:                        // use fallback implementation
0313:                    } catch (IllegalAccessException e) {
0314:                        // use fallback implementation
0315:                    } catch (InvocationTargetException e) {
0316:                        // use fallback implementation
0317:                    } catch (DOMException e) {
0318:                        // use fallback implementation
0319:                    }
0320:                }
0321:
0322:                if (other instanceof  SiblingCountingNode) {
0323:                    return Navigator.compareOrder(this ,
0324:                            (SiblingCountingNode) other);
0325:                } else {
0326:                    // it's presumably a Namespace Node
0327:                    return -other.compareOrder(this );
0328:                }
0329:            }
0330:
0331:            /**
0332:             * Return the string value of the node. The interpretation of this depends on the type
0333:             * of node. For an element it is the accumulated character content of the element,
0334:             * including descendant elements.
0335:             * @return the string value of the node
0336:             */
0337:
0338:            public String getStringValue() {
0339:                return getStringValueCS().toString();
0340:
0341:            }
0342:
0343:            /**
0344:             * Get the value of the item as a CharSequence. This is in some cases more efficient than
0345:             * the version of the method that returns a String.
0346:             */
0347:
0348:            public CharSequence getStringValueCS() {
0349:                //return getStringValue(node, nodeKind);
0350:                switch (nodeKind) {
0351:                case Type.DOCUMENT:
0352:                case Type.ELEMENT:
0353:                    NodeList children1 = node.getChildNodes();
0354:                    StringBuffer sb1 = new StringBuffer(16);
0355:                    expandStringValue(children1, sb1);
0356:                    return sb1;
0357:
0358:                case Type.ATTRIBUTE:
0359:                    return ((Attr) node).getValue();
0360:
0361:                case Type.TEXT:
0362:                    if (span == 1) {
0363:                        return node.getNodeValue();
0364:                    } else {
0365:                        FastStringBuffer fsb = new FastStringBuffer(100);
0366:                        Node textNode = node;
0367:                        for (int i = 0; i < span; i++) {
0368:                            fsb.append(textNode.getNodeValue());
0369:                            textNode = textNode.getNextSibling();
0370:                        }
0371:                        return fsb.condense();
0372:                    }
0373:
0374:                case Type.COMMENT:
0375:                case Type.PROCESSING_INSTRUCTION:
0376:                    return node.getNodeValue();
0377:
0378:                default:
0379:                    return "";
0380:                }
0381:            }
0382:
0383:            /**
0384:             * Get the string value of a DOM node
0385:             * @param node
0386:             * @param nodeKind
0387:             * @return
0388:             */
0389:
0390:            private static CharSequence getStringValue(Node node, int nodeKind) {
0391:                switch (nodeKind) {
0392:                case Type.DOCUMENT:
0393:                case Type.ELEMENT:
0394:                    NodeList children1 = node.getChildNodes();
0395:                    StringBuffer sb1 = new StringBuffer(16);
0396:                    expandStringValue(children1, sb1);
0397:                    return sb1;
0398:
0399:                case Type.ATTRIBUTE:
0400:                    return ((Attr) node).getValue();
0401:
0402:                case Type.TEXT:
0403:                case Node.CDATA_SECTION_NODE:
0404:                    return node.getNodeValue();
0405:
0406:                case Type.COMMENT:
0407:                case Type.PROCESSING_INSTRUCTION:
0408:                    return node.getNodeValue();
0409:
0410:                default:
0411:                    return "";
0412:                }
0413:            }
0414:
0415:            private static void expandStringValue(NodeList list, StringBuffer sb) {
0416:                for (int i = 0; i < list.getLength(); i++) {
0417:                    Node child = list.item(i);
0418:                    switch (child.getNodeType()) {
0419:                    case Node.ELEMENT_NODE:
0420:                        expandStringValue(child.getChildNodes(), sb);
0421:                        break;
0422:                    default:
0423:                        sb.append(child.getNodeValue());
0424:                    }
0425:                }
0426:            }
0427:
0428:            /**
0429:             * Get name code. The name code is a coded form of the node name: two nodes
0430:             * with the same name code have the same namespace URI, the same local name,
0431:             * and the same prefix. By masking the name code with &0xfffff, you get a
0432:             * fingerprint: two nodes with the same fingerprint have the same local name
0433:             * and namespace URI.
0434:             * @see NamePool#allocate allocate
0435:             */
0436:
0437:            public int getNameCode() {
0438:                if (namecode != -1) {
0439:                    // this is a memo function
0440:                    return namecode;
0441:                }
0442:                int nodeKind = getNodeKind();
0443:                if (nodeKind == Type.ELEMENT || nodeKind == Type.ATTRIBUTE) {
0444:                    String prefix = node.getPrefix();
0445:                    if (prefix == null) {
0446:                        prefix = "";
0447:                    }
0448:                    namecode = docWrapper.getNamePool().allocate(prefix,
0449:                            getURI(), getLocalPart());
0450:                    return namecode;
0451:                } else if (nodeKind == Type.PROCESSING_INSTRUCTION) {
0452:                    namecode = docWrapper.getNamePool().allocate("", "",
0453:                            getLocalPart());
0454:                    return namecode;
0455:                } else {
0456:                    return -1;
0457:                }
0458:            }
0459:
0460:            /**
0461:             * Get fingerprint. The fingerprint is a coded form of the expanded name
0462:             * of the node: two nodes
0463:             * with the same name code have the same namespace URI and the same local name.
0464:             * A fingerprint of -1 should be returned for a node with no name.
0465:             */
0466:
0467:            public int getFingerprint() {
0468:                int nc = getNameCode();
0469:                if (nc == -1) {
0470:                    return -1;
0471:                }
0472:                return nc & 0xfffff;
0473:            }
0474:
0475:            /**
0476:             * Get the local part of the name of this node. This is the name after the ":" if any.
0477:             * @return the local part of the name. For an unnamed node, returns null, except for
0478:             * un unnamed namespace node, which returns "".
0479:             */
0480:
0481:            public String getLocalPart() {
0482:                String s = node.getLocalName();
0483:                if (s == null) {
0484:                    // Crimson returns null for the attribute "xml:space": test axes-dom132
0485:                    String n = getDisplayName();
0486:                    int colon = n.indexOf(':');
0487:                    if (colon >= 0) {
0488:                        return n.substring(colon + 1);
0489:                    }
0490:                    return n;
0491:                } else {
0492:                    return s;
0493:                }
0494:            }
0495:
0496:            /**
0497:             * Get the URI part of the name of this node. This is the URI corresponding to the
0498:             * prefix, or the URI of the default namespace if appropriate.
0499:             * @return The URI of the namespace of this node. For an unnamed node,
0500:             *     or for a node with an empty prefix, return an empty
0501:             *     string.
0502:             */
0503:
0504:            public String getURI() {
0505:                NodeInfo element;
0506:                if (nodeKind == Type.ELEMENT) {
0507:                    element = this ;
0508:                } else if (nodeKind == Type.ATTRIBUTE) {
0509:                    element = parent;
0510:                } else {
0511:                    return "";
0512:                }
0513:
0514:                // The DOM methods getPrefix() and getNamespaceURI() do not always
0515:                // return the prefix and the URI; they both return null, unless the
0516:                // prefix and URI have been explicitly set in the node by using DOM
0517:                // level 2 interfaces. There's no obvious way of deciding whether
0518:                // an element whose name has no prefix is in the default namespace,
0519:                // other than searching for a default namespace declaration. So we have to
0520:                // be prepared to search.
0521:
0522:                // If getPrefix() and getNamespaceURI() are non-null, however,
0523:                // we can use the values.
0524:
0525:                String uri = node.getNamespaceURI();
0526:                if (uri != null) {
0527:                    return uri;
0528:                }
0529:
0530:                // Otherwise we have to work it out the hard way...
0531:
0532:                if (node.getNodeName().startsWith("xml:")) {
0533:                    return NamespaceConstant.XML;
0534:                }
0535:
0536:                String[] parts;
0537:                try {
0538:                    parts = Name11Checker.getInstance().getQNameParts(
0539:                            node.getNodeName());
0540:                    // use the XML 1.1 rules: these will do because it should already have been checked
0541:                } catch (QNameException e) {
0542:                    throw new IllegalStateException(
0543:                            "Invalid QName in DOM node. " + e);
0544:                }
0545:
0546:                if (nodeKind == Type.ATTRIBUTE && parts[0].equals("")) {
0547:                    // for an attribute, no prefix means no namespace
0548:                    uri = "";
0549:                } else {
0550:                    AxisIterator nsiter = element.iterateAxis(Axis.NAMESPACE);
0551:                    while (true) {
0552:                        NodeInfo ns = (NodeInfo) nsiter.next();
0553:                        if (ns == null)
0554:                            break;
0555:                        if (ns.getLocalPart().equals(parts[0])) {
0556:                            uri = ns.getStringValue();
0557:                            break;
0558:                        }
0559:                    }
0560:                    if (uri == null) {
0561:                        if (parts[0].equals("")) {
0562:                            uri = "";
0563:                        } else {
0564:                            throw new IllegalStateException(
0565:                                    "Undeclared namespace prefix in DOM input: "
0566:                                            + parts[0]);
0567:                        }
0568:                    }
0569:                }
0570:                return uri;
0571:            }
0572:
0573:            /**
0574:             * Get the prefix of the name of the node. This is defined only for elements and attributes.
0575:             * If the node has no prefix, or for other kinds of node, return a zero-length string.
0576:             * This implementation simply returns the prefix defined in the DOM model; this is nto strictly
0577:             * accurate in all cases, but is good enough for the purpose.
0578:             * @return The prefix of the name of the node.
0579:             */
0580:
0581:            public String getPrefix() {
0582:                return node.getPrefix();
0583:            }
0584:
0585:            /**
0586:             * Get the display name of this node. For elements and attributes this is [prefix:]localname.
0587:             * For unnamed nodes, it is an empty string.
0588:             * @return The display name of this node.
0589:             * For a node with no name, return an empty string.
0590:             */
0591:
0592:            public String getDisplayName() {
0593:                switch (nodeKind) {
0594:                case Type.ELEMENT:
0595:                case Type.ATTRIBUTE:
0596:                case Type.PROCESSING_INSTRUCTION:
0597:                    return node.getNodeName();
0598:                default:
0599:                    return "";
0600:
0601:                }
0602:            }
0603:
0604:            /**
0605:             * Get the NodeInfo object representing the parent of this node
0606:             */
0607:
0608:            public NodeInfo getParent() {
0609:                if (parent == null) {
0610:                    switch (getNodeKind()) {
0611:                    case Type.ATTRIBUTE:
0612:                        parent = makeWrapper(((Attr) node).getOwnerElement(),
0613:                                docWrapper);
0614:                        break;
0615:                    default:
0616:                        Node p = node.getParentNode();
0617:                        if (p == null) {
0618:                            return null;
0619:                        } else {
0620:                            parent = makeWrapper(p, docWrapper);
0621:                        }
0622:                    }
0623:                }
0624:                return parent;
0625:            }
0626:
0627:            /**
0628:             * Get the index position of this node among its siblings (starting from 0).
0629:             * In the case of a text node that maps to several adjacent siblings in the DOM,
0630:             * the numbering actually refers to the position of the underlying DOM nodes;
0631:             * thus the sibling position for the text node is that of the first DOM node
0632:             * to which it relates, and the numbering of subsequent XPath nodes is not necessarily
0633:             * consecutive.
0634:             */
0635:
0636:            public int getSiblingPosition() {
0637:                if (index == -1) {
0638:                    switch (nodeKind) {
0639:                    case Type.ELEMENT:
0640:                    case Type.TEXT:
0641:                    case Type.COMMENT:
0642:                    case Type.PROCESSING_INSTRUCTION:
0643:                        int ix = 0;
0644:                        Node start = node;
0645:                        while (true) {
0646:                            start = start.getPreviousSibling();
0647:                            if (start == null) {
0648:                                index = ix;
0649:                                return ix;
0650:                            }
0651:                            ix++;
0652:                        }
0653:                    case Type.ATTRIBUTE:
0654:                        ix = 0;
0655:                        int fp = getFingerprint();
0656:                        AxisIterator iter = parent.iterateAxis(Axis.ATTRIBUTE);
0657:                        while (true) {
0658:                            NodeInfo n = (NodeInfo) iter.next();
0659:                            if (n == null || n.getFingerprint() == fp) {
0660:                                index = ix;
0661:                                return ix;
0662:                            }
0663:                            ix++;
0664:                        }
0665:
0666:                    case Type.NAMESPACE:
0667:                        ix = 0;
0668:                        fp = getFingerprint();
0669:                        iter = parent.iterateAxis(Axis.NAMESPACE);
0670:                        while (true) {
0671:                            NodeInfo n = (NodeInfo) iter.next();
0672:                            if (n == null || n.getFingerprint() == fp) {
0673:                                index = ix;
0674:                                return ix;
0675:                            }
0676:                            ix++;
0677:                        }
0678:                    default:
0679:                        index = 0;
0680:                        return index;
0681:                    }
0682:                }
0683:                return index;
0684:            }
0685:
0686:            /**
0687:             * Return an iteration over the nodes reached by the given axis from this node
0688:             * @param axisNumber the axis to be used
0689:             * @return a SequenceIterator that scans the nodes reached by the axis in turn.
0690:             */
0691:
0692:            public AxisIterator iterateAxis(byte axisNumber) {
0693:                switch (axisNumber) {
0694:                case Axis.ANCESTOR:
0695:                    if (nodeKind == Type.DOCUMENT)
0696:                        return EmptyIterator.getInstance();
0697:                    return new Navigator.AncestorEnumeration(this , false);
0698:
0699:                case Axis.ANCESTOR_OR_SELF:
0700:                    if (nodeKind == Type.DOCUMENT)
0701:                        return EmptyIterator.getInstance();
0702:                    return new Navigator.AncestorEnumeration(this , true);
0703:
0704:                case Axis.ATTRIBUTE:
0705:                    if (nodeKind != Type.ELEMENT)
0706:                        return EmptyIterator.getInstance();
0707:                    return new AttributeEnumeration(this );
0708:
0709:                case Axis.CHILD:
0710:                    if (hasChildNodes()) {
0711:                        return new ChildEnumeration(this , true, true);
0712:                    } else {
0713:                        return EmptyIterator.getInstance();
0714:                    }
0715:
0716:                case Axis.DESCENDANT:
0717:                    if (hasChildNodes()) {
0718:                        return new Navigator.DescendantEnumeration(this , false,
0719:                                true);
0720:                    } else {
0721:                        return EmptyIterator.getInstance();
0722:                    }
0723:
0724:                case Axis.DESCENDANT_OR_SELF:
0725:                    return new Navigator.DescendantEnumeration(this , true, true);
0726:
0727:                case Axis.FOLLOWING:
0728:                    return new Navigator.FollowingEnumeration(this );
0729:
0730:                case Axis.FOLLOWING_SIBLING:
0731:                    switch (nodeKind) {
0732:                    case Type.DOCUMENT:
0733:                    case Type.ATTRIBUTE:
0734:                    case Type.NAMESPACE:
0735:                        return EmptyIterator.getInstance();
0736:                    default:
0737:                        return new ChildEnumeration(this , false, true);
0738:                    }
0739:
0740:                case Axis.NAMESPACE:
0741:                    if (nodeKind != Type.ELEMENT) {
0742:                        return EmptyIterator.getInstance();
0743:                    }
0744:                    return new NamespaceIterator(this , null);
0745:                    //return new NamespaceEnumeration(this);
0746:
0747:                case Axis.PARENT:
0748:                    getParent();
0749:                    return SingletonIterator.makeIterator(parent);
0750:
0751:                case Axis.PRECEDING:
0752:                    return new Navigator.PrecedingEnumeration(this , false);
0753:
0754:                case Axis.PRECEDING_SIBLING:
0755:                    switch (nodeKind) {
0756:                    case Type.DOCUMENT:
0757:                    case Type.ATTRIBUTE:
0758:                    case Type.NAMESPACE:
0759:                        return EmptyIterator.getInstance();
0760:                    default:
0761:                        return new ChildEnumeration(this , false, false);
0762:                    }
0763:
0764:                case Axis.SELF:
0765:                    return SingletonIterator.makeIterator(this );
0766:
0767:                case Axis.PRECEDING_OR_ANCESTOR:
0768:                    return new Navigator.PrecedingEnumeration(this , true);
0769:
0770:                default:
0771:                    throw new IllegalArgumentException("Unknown axis number "
0772:                            + axisNumber);
0773:                }
0774:            }
0775:
0776:            /**
0777:             * Return an iteration over the nodes reached by the given axis from this node
0778:             * @param axisNumber the axis to be used
0779:             * @param nodeTest A pattern to be matched by the returned nodes
0780:             * @return a SequenceIterator that scans the nodes reached by the axis in turn.
0781:             */
0782:
0783:            public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
0784:                return new Navigator.AxisFilter(iterateAxis(axisNumber),
0785:                        nodeTest);
0786:            }
0787:
0788:            /**
0789:             * Get the value of a given attribute of this node
0790:             * @param fingerprint The fingerprint of the attribute name
0791:             * @return the attribute value if it exists or null if not
0792:             */
0793:
0794:            public String getAttributeValue(int fingerprint) {
0795:                NameTest test = new NameTest(Type.ATTRIBUTE, fingerprint,
0796:                        getNamePool());
0797:                AxisIterator iterator = iterateAxis(Axis.ATTRIBUTE, test);
0798:                NodeInfo attribute = (NodeInfo) iterator.next();
0799:                if (attribute == null) {
0800:                    return null;
0801:                } else {
0802:                    return attribute.getStringValue();
0803:                }
0804:            }
0805:
0806:            /**
0807:             * Get the root node - always a document node with this tree implementation
0808:             * @return the NodeInfo representing the containing document
0809:             */
0810:
0811:            public NodeInfo getRoot() {
0812:                return docWrapper;
0813:            }
0814:
0815:            /**
0816:             * Get the root (document) node
0817:             * @return the DocumentInfo representing the containing document
0818:             */
0819:
0820:            public DocumentInfo getDocumentRoot() {
0821:                return docWrapper;
0822:            }
0823:
0824:            /**
0825:             * Determine whether the node has any children. <br />
0826:             * Note: the result is equivalent to <br />
0827:             * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
0828:             */
0829:
0830:            public boolean hasChildNodes() {
0831:                // In Xerces, an attribute node has child text nodes
0832:                if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
0833:                    return false;
0834:                }
0835:                return node.hasChildNodes();
0836:            }
0837:
0838:            /**
0839:             * Get a character string that uniquely identifies this node.
0840:             * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
0841:             * @return a string that uniquely identifies this node, across all
0842:             * documents
0843:             */
0844:
0845:            public String generateId() {
0846:                return Navigator.getSequentialKey(this );
0847:            }
0848:
0849:            /**
0850:             * Get the document number of the document containing this node. For a free-standing
0851:             * orphan node, just return the hashcode.
0852:             */
0853:
0854:            public int getDocumentNumber() {
0855:                return getDocumentRoot().getDocumentNumber();
0856:            }
0857:
0858:            /**
0859:             * Copy this node to a given outputter (deep copy)
0860:             */
0861:
0862:            public void copy(Receiver out, int whichNamespaces,
0863:                    boolean copyAnnotations, int locationId)
0864:                    throws XPathException {
0865:                Navigator.copy(this , out, docWrapper.getNamePool(),
0866:                        whichNamespaces, copyAnnotations, locationId);
0867:            }
0868:
0869:            /**
0870:             * Output all namespace nodes associated with this element. Does nothing if
0871:             * the node is not an element.
0872:             * @param out The relevant outputter
0873:             * @param includeAncestors True if namespaces declared on ancestor elements must
0874:             */
0875:
0876:            public void sendNamespaceDeclarations(Receiver out,
0877:                    boolean includeAncestors) throws XPathException {
0878:                Navigator
0879:                        .sendNamespaceDeclarations(this , out, includeAncestors);
0880:            }
0881:
0882:            /**
0883:             * Get all namespace undeclarations and undeclarations defined on this element.
0884:             *
0885:             * @param buffer If this is non-null, and the result array fits in this buffer, then the result
0886:             *               may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
0887:             * @return An array of integers representing the namespace declarations and undeclarations present on
0888:             *         this element. For a node other than an element, return null. Otherwise, the returned array is a
0889:             *         sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
0890:             *         top half word of each namespace code represents the prefix, the bottom half represents the URI.
0891:             *         If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
0892:             *         The XML namespace is never included in the list. If the supplied array is larger than required,
0893:             *         then the first unused entry will be set to -1.
0894:             *         <p/>
0895:             *         <p>For a node other than an element, the method returns null.</p>
0896:             */
0897:
0898:            public int[] getDeclaredNamespaces(int[] buffer) {
0899:                if (node.getNodeType() == Node.ELEMENT_NODE) {
0900:                    Element elem = (Element) node;
0901:                    NamedNodeMap atts = elem.getAttributes();
0902:
0903:                    if (atts == null) {
0904:                        return EMPTY_NAMESPACE_LIST;
0905:                    }
0906:                    int count = 0;
0907:                    for (int i = 0; i < atts.getLength(); i++) {
0908:                        Attr att = (Attr) atts.item(i);
0909:                        String attName = att.getName();
0910:                        if (attName.equals("xmlns")) {
0911:                            count++;
0912:                        } else if (attName.startsWith("xmlns:")) {
0913:                            count++;
0914:                        }
0915:                    }
0916:                    if (count == 0) {
0917:                        return EMPTY_NAMESPACE_LIST;
0918:                    } else {
0919:                        int[] result = (count > buffer.length ? new int[count]
0920:                                : buffer);
0921:                        NamePool pool = getNamePool();
0922:                        int n = 0;
0923:                        for (int i = 0; i < atts.getLength(); i++) {
0924:                            Attr att = (Attr) atts.item(i);
0925:                            String attName = att.getName();
0926:                            if (attName.equals("xmlns")) {
0927:                                String prefix = "";
0928:                                String uri = att.getValue();
0929:                                result[n++] = pool.allocateNamespaceCode(
0930:                                        prefix, uri);
0931:                            } else if (attName.startsWith("xmlns:")) {
0932:                                String prefix = attName.substring(6);
0933:                                String uri = att.getValue();
0934:                                result[n++] = pool.allocateNamespaceCode(
0935:                                        prefix, uri);
0936:                            }
0937:                        }
0938:                        if (count < result.length) {
0939:                            result[count] = -1;
0940:                        }
0941:                        return result;
0942:                    }
0943:                } else {
0944:                    return null;
0945:                }
0946:            }
0947:
0948:            private final class AttributeEnumeration implements  AxisIterator,
0949:                    LookaheadIterator {
0950:
0951:                private ArrayList attList = new ArrayList(10);
0952:                private int ix = 0;
0953:                private NodeWrapper start;
0954:                private NodeWrapper current;
0955:
0956:                public AttributeEnumeration(NodeWrapper start) {
0957:                    this .start = start;
0958:                    NamedNodeMap atts = start.node.getAttributes();
0959:                    if (atts != null) {
0960:                        for (int i = 0; i < atts.getLength(); i++) {
0961:                            String name = atts.item(i).getNodeName();
0962:                            if (!(name.startsWith("xmlns") && (name.length() == 5 || name
0963:                                    .charAt(5) == ':'))) {
0964:                                attList.add(atts.item(i));
0965:                            }
0966:                        }
0967:                    }
0968:                    ix = 0;
0969:                }
0970:
0971:                public boolean hasNext() {
0972:                    return ix < attList.size();
0973:                }
0974:
0975:                public Item next() {
0976:                    if (ix >= attList.size()) {
0977:                        return null;
0978:                    }
0979:                    current = start.makeWrapper((Attr) attList.get(ix),
0980:                            docWrapper, start, ix);
0981:                    ix++;
0982:                    return current;
0983:                }
0984:
0985:                public Item current() {
0986:                    return current;
0987:                }
0988:
0989:                public int position() {
0990:                    return ix + 1;
0991:                }
0992:
0993:                public SequenceIterator getAnother() {
0994:                    return new AttributeEnumeration(start);
0995:                }
0996:
0997:                /**
0998:                 * Get properties of this iterator, as a bit-significant integer.
0999:                 *
1000:                 * @return the properties of this iterator. This will be some combination of
1001:                 *         properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
1002:                 *         and {@link LOOKAHEAD}. It is always
1003:                 *         acceptable to return the value zero, indicating that there are no known special properties.
1004:                 *         It is acceptable for the properties of the iterator to change depending on its state.
1005:                 */
1006:
1007:                public int getProperties() {
1008:                    return LOOKAHEAD;
1009:                }
1010:            }
1011:
1012:            /**
1013:             * The class ChildEnumeration handles not only the child axis, but also the
1014:             * following-sibling and preceding-sibling axes. It can also iterate the children
1015:             * of the start node in reverse order, something that is needed to support the
1016:             * preceding and preceding-or-ancestor axes (the latter being used by xsl:number)
1017:             */
1018:
1019:            private final class ChildEnumeration extends AxisIteratorImpl
1020:                    implements  LookaheadIterator {
1021:
1022:                private NodeWrapper start;
1023:                private NodeWrapper commonParent;
1024:                private ArrayList items = new ArrayList(20);
1025:                private int ix = 0;
1026:                private boolean downwards; // iterate children of start node (not siblings)
1027:                private boolean forwards; // iterate in document order (not reverse order)
1028:
1029:                public ChildEnumeration(NodeWrapper start, boolean downwards,
1030:                        boolean forwards) {
1031:                    this .start = start;
1032:                    this .downwards = downwards;
1033:                    this .forwards = forwards;
1034:                    position = 0;
1035:
1036:                    if (downwards) {
1037:                        commonParent = start;
1038:                    } else {
1039:                        commonParent = (NodeWrapper) start.getParent();
1040:                    }
1041:
1042:                    NodeList childNodes = commonParent.node.getChildNodes();
1043:                    if (downwards) {
1044:                        if (!forwards) {
1045:                            // backwards enumeration: go to the end
1046:                            ix = childNodes.getLength() - 1;
1047:                        }
1048:                    } else {
1049:                        ix = start.getSiblingPosition()
1050:                                + (forwards ? span : -1);
1051:                    }
1052:
1053:                    if (forwards) {
1054:                        boolean previousText = false;
1055:                        for (int i = ix; i < childNodes.getLength(); i++) {
1056:                            boolean this Text = false;
1057:                            Node node = childNodes.item(i);
1058:                            switch (node.getNodeType()) {
1059:                            case Node.DOCUMENT_TYPE_NODE:
1060:                                break;
1061:                            case Node.TEXT_NODE:
1062:                            case Node.CDATA_SECTION_NODE:
1063:                                this Text = true;
1064:                                if (previousText) {
1065:                                    if (isAtomizing()) {
1066:                                        UntypedAtomicValue old = (UntypedAtomicValue) (items
1067:                                                .get(items.size() - 1));
1068:                                        String newval = old.getStringValue()
1069:                                                + getStringValue(node, node
1070:                                                        .getNodeType());
1071:                                        items.set(items.size() - 1,
1072:                                                new UntypedAtomicValue(newval));
1073:                                    } else {
1074:                                        NodeWrapper old = ((NodeWrapper) items
1075:                                                .get(items.size() - 1));
1076:                                        old.span++;
1077:                                    }
1078:                                    break;
1079:                                }
1080:                                // otherwise fall through to default case
1081:                            default:
1082:                                previousText = this Text;
1083:                                if (isAtomizing()) {
1084:                                    items.add(new UntypedAtomicValue(
1085:                                            getStringValue(node, node
1086:                                                    .getNodeType())));
1087:                                } else {
1088:                                    items.add(makeWrapper(node, docWrapper,
1089:                                            commonParent, i));
1090:                                }
1091:                            }
1092:                        }
1093:                    } else {
1094:                        boolean previousText = false;
1095:                        for (int i = ix; i >= 0; i--) {
1096:                            boolean this Text = false;
1097:                            Node node = childNodes.item(i);
1098:                            switch (node.getNodeType()) {
1099:                            case Node.DOCUMENT_TYPE_NODE:
1100:                                break;
1101:                            case Node.TEXT_NODE:
1102:                            case Node.CDATA_SECTION_NODE:
1103:                                this Text = true;
1104:                                if (previousText) {
1105:                                    if (isAtomizing()) {
1106:                                        UntypedAtomicValue old = (UntypedAtomicValue) (items
1107:                                                .get(items.size() - 1));
1108:                                        String newval = old.getStringValue()
1109:                                                + getStringValue(node, node
1110:                                                        .getNodeType());
1111:                                        items.set(items.size() - 1,
1112:                                                new UntypedAtomicValue(newval));
1113:                                    } else {
1114:                                        NodeWrapper old = ((NodeWrapper) items
1115:                                                .get(items.size() - 1));
1116:                                        old.node = node;
1117:                                        old.span++;
1118:                                    }
1119:                                    break;
1120:                                }
1121:                                // otherwise fall through to default case
1122:                            default:
1123:                                previousText = this Text;
1124:                                if (isAtomizing()) {
1125:                                    items.add(new UntypedAtomicValue(
1126:                                            getStringValue(node, node
1127:                                                    .getNodeType())));
1128:                                } else {
1129:                                    items.add(makeWrapper(node, docWrapper,
1130:                                            commonParent, i));
1131:                                }
1132:                            }
1133:                        }
1134:                    }
1135:                }
1136:
1137:                public boolean hasNext() {
1138:                    return position < items.size();
1139:                }
1140:
1141:                public Item next() {
1142:                    if (position < items.size()) {
1143:                        current = (Item) items.get(position++);
1144:                        return current;
1145:                    } else {
1146:                        return null;
1147:                    }
1148:                }
1149:
1150:                public SequenceIterator getAnother() {
1151:                    return new ChildEnumeration(start, downwards, forwards);
1152:                }
1153:
1154:                /**
1155:                 * Get properties of this iterator, as a bit-significant integer.
1156:                 *
1157:                 * @return the properties of this iterator. This will be some combination of
1158:                 *         properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
1159:                 *         and {@link LOOKAHEAD}. It is always
1160:                 *         acceptable to return the value zero, indicating that there are no known special properties.
1161:                 *         It is acceptable for the properties of the iterator to change depending on its state.
1162:                 */
1163:
1164:                public int getProperties() {
1165:                    return LOOKAHEAD;
1166:                }
1167:
1168:            } // end of class ChildEnumeration
1169:
1170:        }
1171:
1172:        //
1173:        // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1174:        // you may not use this file except in compliance with the License. You may obtain a copy of the
1175:        // License at http://www.mozilla.org/MPL/
1176:        //
1177:        // Software distributed under the License is distributed on an "AS IS" basis,
1178:        // WITHOUT WARRANTY OF ANY KIND, either express or implied.
1179:        // See the License for the specific language governing rights and limitations under the License.
1180:        //
1181:        // The Original Code is: all this file.
1182:        //
1183:        // The Initial Developer of the Original Code is Michael Kay
1184:        //
1185:        // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1186:        //
1187:        // Contributor(s): none.
1188:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.