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


0001:        package net.sf.saxon.om;
0002:
0003:        import net.sf.saxon.Controller;
0004:        import net.sf.saxon.event.Receiver;
0005:        import net.sf.saxon.expr.Expression;
0006:        import net.sf.saxon.expr.ReversibleIterator;
0007:        import net.sf.saxon.expr.XPathContext;
0008:        import net.sf.saxon.functions.EscapeURI;
0009:        import net.sf.saxon.pattern.*;
0010:        import net.sf.saxon.style.StandardNames;
0011:        import net.sf.saxon.trans.XPathException;
0012:        import net.sf.saxon.type.Type;
0013:        import net.sf.saxon.value.SequenceExtent;
0014:        import net.sf.saxon.value.Whitespace;
0015:
0016:        import java.net.URI;
0017:        import java.net.URISyntaxException;
0018:        import java.util.ArrayList;
0019:        import java.util.List;
0020:
0021:        /**
0022:         * The Navigator class provides helper classes for navigating a tree, irrespective
0023:         * of its implementation
0024:         *
0025:         * @author Michael H. Kay
0026:         */
0027:
0028:        public final class Navigator {
0029:
0030:            // Class is never instantiated
0031:            private Navigator() {
0032:            }
0033:
0034:            /**
0035:             * Get the string value of an attribute of a given element, given the URI and
0036:             * local part of the attribute name.
0037:             * @return the attribute value, or null if the attribute is not present
0038:             */
0039:
0040:            public static String getAttributeValue(NodeInfo element,
0041:                    String uri, String localName) {
0042:                int fingerprint = element.getNamePool().allocate("", uri,
0043:                        localName);
0044:                return element.getAttributeValue(fingerprint);
0045:            }
0046:
0047:            /**
0048:             * Helper method to get the base URI of an element node
0049:             */
0050:
0051:            public static String getBaseURI(NodeInfo element) {
0052:                String xmlBase = element
0053:                        .getAttributeValue(StandardNames.XML_BASE);
0054:                if (xmlBase != null) {
0055:                    String escaped = EscapeURI.escape(xmlBase, false)
0056:                            .toString();
0057:                    URI escapedURI;
0058:                    try {
0059:                        escapedURI = new URI(escaped);
0060:                        if (!escapedURI.isAbsolute()) {
0061:                            NodeInfo parent = element.getParent();
0062:                            if (parent == null) {
0063:                                return escapedURI.toString();
0064:                            }
0065:                            String startSystemId = element.getSystemId();
0066:                            String parentSystemId = parent.getSystemId();
0067:                            if (startSystemId.equals(parentSystemId)) {
0068:                                URI base = new URI(element.getParent()
0069:                                        .getBaseURI());
0070:                                escapedURI = base.resolve(escapedURI);
0071:                            } else {
0072:                                URI base = new URI(startSystemId);
0073:                                escapedURI = base.resolve(escapedURI);
0074:                            }
0075:                        }
0076:                    } catch (URISyntaxException e) {
0077:                        // xml:base is an invalid URI. Just return it as is: the operation that needs the base URI
0078:                        // will probably fail as a result.
0079:                        return xmlBase;
0080:                    }
0081:                    return escapedURI.toString();
0082:                }
0083:                String startSystemId = element.getSystemId();
0084:                NodeInfo parent = element.getParent();
0085:                if (parent == null) {
0086:                    return startSystemId;
0087:                }
0088:                String parentSystemId = parent.getSystemId();
0089:                if (startSystemId.equals(parentSystemId)) {
0090:                    return parent.getBaseURI();
0091:                } else {
0092:                    return startSystemId;
0093:                }
0094:            }
0095:
0096:            /**
0097:             * Output all namespace nodes associated with this element. Does nothing if
0098:             * the node is not an element. This is a helper method to allow the method
0099:             * {@link NodeInfo#sendNamespaceDeclarations(net.sf.saxon.event.Receiver, boolean)} to be
0100:             * implemented if {@link NodeInfo#getDeclaredNamespaces(int[])} is available.
0101:             * @param out The relevant outputter
0102:             * @param includeAncestors True if namespaces declared on ancestor elements must be output
0103:             */
0104:
0105:            public static void sendNamespaceDeclarations(NodeInfo node,
0106:                    Receiver out, boolean includeAncestors)
0107:                    throws XPathException {
0108:                if (node.getNodeKind() == Type.ELEMENT) {
0109:                    int[] codes;
0110:                    if (includeAncestors) {
0111:                        codes = new NamespaceIterator(node, null)
0112:                                .getInScopeNamespaceCodes();
0113:                    } else {
0114:                        codes = node
0115:                                .getDeclaredNamespaces(NodeInfo.EMPTY_NAMESPACE_LIST);
0116:                    }
0117:                    for (int i = 0; i < codes.length; i++) {
0118:                        if (codes[i] == -1)
0119:                            break;
0120:                        out.namespace(codes[i], 0);
0121:                    }
0122:                }
0123:            }
0124:
0125:            /**
0126:             * Get an absolute XPath expression that identifies a given node within its document
0127:             *
0128:             * @param node the node whose path is required. If null is supplied,
0129:             * an empty string is returned - this fact is used in making a recursive call
0130:             * for a parentless node.
0131:             * @return a path expression that can be used to retrieve the node
0132:             */
0133:
0134:            public static String getPath(NodeInfo node) {
0135:                if (node == null) {
0136:                    return "";
0137:                }
0138:                String pre;
0139:                NodeInfo parent = node.getParent();
0140:                // System.err.println("node = " + node + " parent = " + parent);
0141:
0142:                switch (node.getNodeKind()) {
0143:                case Type.DOCUMENT:
0144:                    return "/";
0145:                case Type.ELEMENT:
0146:                    if (parent == null) {
0147:                        return node.getDisplayName();
0148:                    } else {
0149:                        pre = getPath(parent);
0150:                        if (pre.equals("/")) {
0151:                            return '/' + node.getDisplayName();
0152:                        } else {
0153:                            return pre + '/' + node.getDisplayName() + '['
0154:                                    + getNumberSimple(node) + ']';
0155:                        }
0156:                    }
0157:                case Type.ATTRIBUTE:
0158:                    return getPath(parent) + "/@" + node.getDisplayName();
0159:                case Type.TEXT:
0160:                    pre = getPath(parent);
0161:                    return (pre.equals("/") ? "" : pre) + "/text()["
0162:                            + getNumberSimple(node) + ']';
0163:                case Type.COMMENT:
0164:                    pre = getPath(parent);
0165:                    return (pre.equals("/") ? "" : pre) + "/comment()["
0166:                            + getNumberSimple(node) + ']';
0167:                case Type.PROCESSING_INSTRUCTION:
0168:                    pre = getPath(parent);
0169:                    return (pre.equals("/") ? "" : pre)
0170:                            + "/processing-instruction()["
0171:                            + getNumberSimple(node) + ']';
0172:                case Type.NAMESPACE:
0173:                    String test = node.getLocalPart();
0174:                    if (test.equals("")) {
0175:                        // default namespace: need a node-test that selects unnamed nodes only
0176:                        test = "*[not(local-name()]";
0177:                    }
0178:                    return getPath(parent) + "/namespace::" + test;
0179:                default:
0180:                    return "";
0181:                }
0182:            }
0183:
0184:            /**
0185:             * Get simple node number. This is defined as one plus the number of previous siblings of the
0186:             * same node type and name. It is not accessible directly in XSL.
0187:             *
0188:             * @param node The node whose number is required
0189:             * @param context Used for remembering previous result, for
0190:             *     performance
0191:             * @exception XPathException if any error occurs
0192:             * @return the node number, as defined above
0193:             */
0194:
0195:            public static int getNumberSimple(NodeInfo node,
0196:                    XPathContext context) throws XPathException {
0197:
0198:                //checkNumberable(node);
0199:
0200:                int fingerprint = node.getFingerprint();
0201:                NodeTest same;
0202:
0203:                if (fingerprint == -1) {
0204:                    same = NodeKindTest.makeNodeKindTest(node.getNodeKind());
0205:                } else {
0206:                    same = new NameTest(node);
0207:                }
0208:
0209:                SequenceIterator preceding = node.iterateAxis(
0210:                        Axis.PRECEDING_SIBLING, same);
0211:
0212:                int i = 1;
0213:                while (true) {
0214:                    NodeInfo prev = (NodeInfo) preceding.next();
0215:                    if (prev == null) {
0216:                        break;
0217:                    }
0218:
0219:                    Controller controller = context.getController();
0220:                    int memo = controller.getRememberedNumber(prev);
0221:                    if (memo > 0) {
0222:                        memo += i;
0223:                        controller.setRememberedNumber(node, memo);
0224:                        return memo;
0225:                    }
0226:
0227:                    i++;
0228:                }
0229:
0230:                context.getController().setRememberedNumber(node, i);
0231:                return i;
0232:            }
0233:
0234:            /**
0235:             * Get simple node number. This is defined as one plus the number of previous siblings of the
0236:             * same node type and name. It is not accessible directly in XSL. This version doesn't require
0237:             * the controller, and therefore doesn't remember previous results. It is used only by getPath().
0238:             *
0239:             * @param node the node whose number is required
0240:             * @return the node number, as defined above
0241:             */
0242:
0243:            private static int getNumberSimple(NodeInfo node) {
0244:
0245:                int fingerprint = node.getFingerprint();
0246:                NodeTest same;
0247:
0248:                if (fingerprint == -1) {
0249:                    same = NodeKindTest.makeNodeKindTest(node.getNodeKind());
0250:                } else {
0251:                    same = new NameTest(node);
0252:                }
0253:
0254:                AxisIterator preceding = node.iterateAxis(
0255:                        Axis.PRECEDING_SIBLING, same);
0256:
0257:                int i = 1;
0258:                while (preceding.next() != null) {
0259:                    i++;
0260:                }
0261:
0262:                return i;
0263:            }
0264:
0265:            /**
0266:             * Get node number (level="single"). If the current node matches the supplied pattern, the returned
0267:             * number is one plus the number of previous siblings that match the pattern. Otherwise,
0268:             * return the element number of the nearest ancestor that matches the supplied pattern.
0269:             *
0270:             * @param node the current node, the one whose node number is required
0271:             * @param count Pattern that identifies which nodes should be
0272:             *     counted. Default (null) is the element name if the current node is
0273:             *      an element, or "node()" otherwise.
0274:             * @param from Pattern that specifies where counting starts from.
0275:             *     Default (null) is the root node. (This parameter does not seem
0276:             *     useful but is included for the sake of XSLT conformance.)
0277:             * @param context the dynamic context of the transformation, used if
0278:             *     the patterns reference context values (e.g. variables)
0279:             * @exception XPathException when any error occurs in processing
0280:             * @return the node number established as follows: go to the nearest
0281:             *     ancestor-or-self that matches the 'count' pattern and that is a
0282:             *     descendant of the nearest ancestor that matches the 'from' pattern.
0283:             *      Return one plus the nunber of preceding siblings of that ancestor
0284:             *      that match the 'count' pattern. If there is no such ancestor,
0285:             *     return 0.
0286:             */
0287:
0288:            public static int getNumberSingle(NodeInfo node, Pattern count,
0289:                    Pattern from, XPathContext context) throws XPathException {
0290:
0291:                if (count == null && from == null) {
0292:                    return getNumberSimple(node, context);
0293:                }
0294:
0295:                boolean knownToMatch = false;
0296:                if (count == null) {
0297:                    if (node.getFingerprint() == -1) { // unnamed node
0298:                        count = new NodeTestPattern(NodeKindTest
0299:                                .makeNodeKindTest(node.getNodeKind()));
0300:                    } else {
0301:                        count = new NodeTestPattern(new NameTest(node));
0302:                    }
0303:                    knownToMatch = true;
0304:                }
0305:
0306:                NodeInfo target = node;
0307:                while (!(knownToMatch || count.matches(target, context))) {
0308:                    target = target.getParent();
0309:                    if (target == null) {
0310:                        return 0;
0311:                    }
0312:                    if (from != null && from.matches(target, context)) {
0313:                        return 0;
0314:                    }
0315:                }
0316:
0317:                // we've found the ancestor to count from
0318:
0319:                SequenceIterator preceding = target.iterateAxis(
0320:                        Axis.PRECEDING_SIBLING, count.getNodeTest());
0321:                // pass the filter condition down to the axis enumeration where possible
0322:                boolean alreadyChecked = (count instanceof  NodeTestPattern);
0323:                int i = 1;
0324:                while (true) {
0325:                    NodeInfo p = (NodeInfo) preceding.next();
0326:                    if (p == null) {
0327:                        return i;
0328:                    }
0329:                    if (alreadyChecked || count.matches(p, context)) {
0330:                        i++;
0331:                    }
0332:                }
0333:            }
0334:
0335:            /**
0336:             * Get node number (level="any").
0337:             * Return one plus the number of previous nodes in the
0338:             * document that match the supplied pattern
0339:             *
0340:             * @exception net.sf.saxon.trans.XPathException
0341:             * @param inst Identifies the xsl:number expression; this is relevant
0342:             *     when the function is memoised to support repeated use of the same
0343:             *     instruction to number multiple nodes
0344:             * @param node The node being numbered
0345:             * @param count Pattern that identifies which nodes should be
0346:             *     counted. Default (null) is the element name if the current node is
0347:             *      an element, or "node()" otherwise.
0348:             * @param from Pattern that specifies where counting starts from.
0349:             *     Default (null) is the root node. Only nodes after the first (most
0350:             *     recent) node that matches the 'from' pattern are counted.
0351:             * @param context The dynamic context for the transformation
0352:             * @param hasVariablesInPatterns if the count or from patterns
0353:             *     contain variables, then it's not safe to get the answer by adding
0354:             *     one to the number of the most recent node that matches
0355:             * @return one plus the number of nodes that precede the current node,
0356:             *     that match the count pattern, and that follow the first node that
0357:             *     matches the from pattern if specified.
0358:             */
0359:
0360:            public static int getNumberAny(Expression inst, NodeInfo node,
0361:                    Pattern count, Pattern from, XPathContext context,
0362:                    boolean hasVariablesInPatterns) throws XPathException {
0363:
0364:                NodeInfo memoNode = null;
0365:                int memoNumber = 0;
0366:                Controller controller = context.getController();
0367:                boolean memoise = (!hasVariablesInPatterns && count != null);
0368:                if (memoise) {
0369:                    Object[] memo = (Object[]) controller.getUserData(inst,
0370:                            "xsl:number");
0371:                    if (memo != null) {
0372:                        memoNode = (NodeInfo) memo[0];
0373:                        memoNumber = ((Integer) memo[1]).intValue();
0374:                    }
0375:                }
0376:
0377:                int num = 0;
0378:                if (count == null) {
0379:                    if (node.getFingerprint() == -1) { // unnamed node
0380:                        count = new NodeTestPattern(NodeKindTest
0381:                                .makeNodeKindTest(node.getNodeKind()));
0382:                    } else {
0383:                        count = new NodeTestPattern(new NameTest(node));
0384:                    }
0385:                    num = 1;
0386:                } else if (count.matches(node, context)) {
0387:                    num = 1;
0388:                }
0389:
0390:                // We use a special axis invented for the purpose: the union of the preceding and
0391:                // ancestor axes, but in reverse document order
0392:
0393:                // Pass part of the filtering down to the axis iterator if possible
0394:                NodeTest filter;
0395:                if (from == null) {
0396:                    filter = count.getNodeTest();
0397:                } else if (from.getNodeKind() == Type.ELEMENT
0398:                        && count.getNodeKind() == Type.ELEMENT) {
0399:                    filter = NodeKindTest.ELEMENT;
0400:                } else {
0401:                    filter = AnyNodeTest.getInstance();
0402:                }
0403:
0404:                SequenceIterator preceding = node.iterateAxis(
0405:                        Axis.PRECEDING_OR_ANCESTOR, filter);
0406:
0407:                while (true) {
0408:                    NodeInfo prev = (NodeInfo) preceding.next();
0409:                    if (prev == null) {
0410:                        break;
0411:                    }
0412:                    if (from != null && from.matches(prev, context)) {
0413:                        return num;
0414:                    }
0415:                    if (count.matches(prev, context)) {
0416:                        if (num == 1 && memoNode != null
0417:                                && prev.isSameNodeInfo(memoNode)) {
0418:                            num = memoNumber + 1;
0419:                            break;
0420:                        }
0421:                        num++;
0422:                    }
0423:                }
0424:                if (from != null) {
0425:                    // we've got to the end without matching the from pattern - result is ()
0426:                    return 0;
0427:                }
0428:                if (memoise) {
0429:                    Object[] memo = new Object[2];
0430:                    memo[0] = node;
0431:                    memo[1] = new Integer(num);
0432:                    controller.setUserData(inst, "xsl:number", memo);
0433:                }
0434:                return num;
0435:            }
0436:
0437:            /**
0438:             * Get node number (level="multiple").
0439:             * Return a vector giving the hierarchic position of this node. See the XSLT spec for details.
0440:             *
0441:             * @exception XPathException
0442:             * @param node The node to be numbered
0443:             * @param count Pattern that identifies which nodes (ancestors and
0444:             *      their previous siblings) should be counted. Default (null) is the
0445:             *      element name if the current node is an element, or "node()"
0446:             *     otherwise.
0447:             * @param from Pattern that specifies where counting starts from.
0448:             *     Default (null) is the root node. Only nodes below the first (most
0449:             *     recent) node that matches the 'from' pattern are counted.
0450:             * @param context The dynamic context for the transformation
0451:             * @return a vector containing for each ancestor-or-self that matches the
0452:             *      count pattern and that is below the nearest node that matches the
0453:             *      from pattern, an Integer which is one greater than the number of
0454:             *     previous siblings that match the count pattern.
0455:             */
0456:
0457:            public static List getNumberMulti(NodeInfo node, Pattern count,
0458:                    Pattern from, XPathContext context) throws XPathException {
0459:
0460:                //checkNumberable(node);
0461:
0462:                ArrayList v = new ArrayList(5);
0463:
0464:                if (count == null) {
0465:                    if (node.getFingerprint() == -1) { // unnamed node
0466:                        count = new NodeTestPattern(NodeKindTest
0467:                                .makeNodeKindTest(node.getNodeKind()));
0468:                    } else {
0469:                        count = new NodeTestPattern(new NameTest(node));
0470:                    }
0471:                }
0472:
0473:                NodeInfo curr = node;
0474:
0475:                while (true) {
0476:                    if (count.matches(curr, context)) {
0477:                        int num = getNumberSingle(curr, count, null, context);
0478:                        v.add(0, new Long(num));
0479:                    }
0480:                    curr = curr.getParent();
0481:                    if (curr == null)
0482:                        break;
0483:                    if (from != null && from.matches(curr, context))
0484:                        break;
0485:                }
0486:
0487:                return v;
0488:            }
0489:
0490:            /**
0491:             * Generic (model-independent) implementation of deep copy algorithm for nodes.
0492:             * This is available for use by any node implementations that choose to use it.
0493:             * @param node The node to be copied
0494:             * @param out The receiver to which events will be sent
0495:             * @param namePool Namepool holding the name codes (used only to resolve namespace
0496:             *          codes)
0497:             * @param whichNamespaces Indicates which namespace nodes for an element should
0498:             *          be copied
0499:             * @param copyAnnotations Indicates whether type annotations should be copied
0500:             * @throws XPathException on any failure reported by the Receiver
0501:             */
0502:
0503:            public static void copy(NodeInfo node, Receiver out,
0504:                    NamePool namePool, int whichNamespaces,
0505:                    boolean copyAnnotations, int locationId)
0506:                    throws XPathException {
0507:
0508:                switch (node.getNodeKind()) {
0509:                case Type.DOCUMENT: {
0510:                    out.startDocument(0);
0511:                    AxisIterator children0 = node.iterateAxis(Axis.CHILD,
0512:                            new AnyNodeTest());
0513:                    while (true) {
0514:                        NodeInfo child = (NodeInfo) children0.next();
0515:                        if (child == null) {
0516:                            break;
0517:                        }
0518:                        child.copy(out, whichNamespaces, copyAnnotations,
0519:                                locationId);
0520:                    }
0521:                    out.endDocument();
0522:                    break;
0523:                }
0524:                case Type.ELEMENT: {
0525:                    out.startElement(node.getNameCode(), copyAnnotations ? node
0526:                            .getTypeAnnotation() : StandardNames.XDT_UNTYPED,
0527:                            0, 0);
0528:
0529:                    // output the namespaces
0530:
0531:                    if (whichNamespaces != NodeInfo.NO_NAMESPACES) {
0532:                        node.sendNamespaceDeclarations(out, true);
0533:                    }
0534:
0535:                    // output the attributes
0536:
0537:                    AxisIterator attributes = node.iterateAxis(Axis.ATTRIBUTE,
0538:                            new AnyNodeTest());
0539:                    while (true) {
0540:                        NodeInfo att = (NodeInfo) attributes.next();
0541:                        if (att == null) {
0542:                            break;
0543:                        }
0544:                        att.copy(out, whichNamespaces, copyAnnotations,
0545:                                locationId);
0546:                    }
0547:
0548:                    // notify the start of content
0549:
0550:                    out.startContent();
0551:
0552:                    // output the children
0553:
0554:                    AxisIterator children = node.iterateAxis(Axis.CHILD,
0555:                            new AnyNodeTest());
0556:                    while (true) {
0557:                        NodeInfo child = (NodeInfo) children.next();
0558:                        if (child == null) {
0559:                            break;
0560:                        }
0561:                        child.copy(out, whichNamespaces, copyAnnotations,
0562:                                locationId);
0563:                    }
0564:
0565:                    // finally the end tag
0566:
0567:                    out.endElement();
0568:                    return;
0569:                }
0570:                case Type.ATTRIBUTE: {
0571:                    out.attribute(node.getNameCode(), copyAnnotations ? node
0572:                            .getTypeAnnotation()
0573:                            : StandardNames.XDT_UNTYPED_ATOMIC, node
0574:                            .getStringValueCS(), 0, 0);
0575:                    return;
0576:                }
0577:                case Type.TEXT: {
0578:                    out.characters(node.getStringValueCS(), 0, 0);
0579:                    return;
0580:                }
0581:                case Type.COMMENT: {
0582:                    out.comment(node.getStringValueCS(), 0, 0);
0583:                    return;
0584:                }
0585:                case Type.PROCESSING_INSTRUCTION: {
0586:                    out.processingInstruction(node.getLocalPart(), node
0587:                            .getStringValueCS(), 0, 0);
0588:                    return;
0589:                }
0590:                case Type.NAMESPACE: {
0591:                    out.namespace(namePool.allocateNamespaceCode(node
0592:                            .getLocalPart(), node.getStringValue()), 0);
0593:                    return;
0594:                }
0595:                default:
0596:
0597:                }
0598:            }
0599:
0600:            /**
0601:             * Generic (model-independent) method to determine the relative position of two
0602:             * node in document order. The nodes must be in the same tree.
0603:             * @param first The first node
0604:             * @param second The second node, whose position is to be compared with the first node
0605:             * @return -1 if this node precedes the other node, +1 if it follows the other
0606:             * node, or 0 if they are the same node. (In this case, isSameNode() will always
0607:             * return true, and the two nodes will produce the same result for generateId())
0608:             */
0609:
0610:            public static int compareOrder(SiblingCountingNode first,
0611:                    SiblingCountingNode second) {
0612:                NodeInfo ow = second;
0613:
0614:                // are they the same node?
0615:                if (first.isSameNodeInfo(second)) {
0616:                    return 0;
0617:                }
0618:
0619:                NodeInfo firstParent = first.getParent();
0620:                if (firstParent == null) {
0621:                    // first node is the root
0622:                    return -1;
0623:                }
0624:
0625:                NodeInfo secondParent = second.getParent();
0626:                if (secondParent == null) {
0627:                    // second node is the root
0628:                    return +1;
0629:                }
0630:
0631:                // do they have the same parent (common case)?
0632:                if (firstParent.isSameNodeInfo(secondParent)) {
0633:                    int cat1 = nodeCategories[first.getNodeKind()];
0634:                    int cat2 = nodeCategories[second.getNodeKind()];
0635:                    if (cat1 == cat2) {
0636:                        return first.getSiblingPosition()
0637:                                - second.getSiblingPosition();
0638:                    } else {
0639:                        return cat1 - cat2;
0640:                    }
0641:                }
0642:
0643:                // find the depths of both nodes in the tree
0644:                int depth1 = 0;
0645:                int depth2 = 0;
0646:                NodeInfo p1 = first;
0647:                NodeInfo p2 = second;
0648:                while (p1 != null) {
0649:                    depth1++;
0650:                    p1 = p1.getParent();
0651:                }
0652:                while (p2 != null) {
0653:                    depth2++;
0654:                    p2 = p2.getParent();
0655:                }
0656:                // move up one branch of the tree so we have two nodes on the same level
0657:
0658:                p1 = first;
0659:                while (depth1 > depth2) {
0660:                    p1 = p1.getParent();
0661:                    if (p1.isSameNodeInfo(second)) {
0662:                        return +1;
0663:                    }
0664:                    depth1--;
0665:                }
0666:
0667:                p2 = ow;
0668:                while (depth2 > depth1) {
0669:                    p2 = p2.getParent();
0670:                    if (p2.isSameNodeInfo(first)) {
0671:                        return -1;
0672:                    }
0673:                    depth2--;
0674:                }
0675:
0676:                // now move up both branches in sync until we find a common parent
0677:                while (true) {
0678:                    NodeInfo par1 = p1.getParent();
0679:                    NodeInfo par2 = p2.getParent();
0680:                    if (par1 == null || par2 == null) {
0681:                        throw new NullPointerException(
0682:                                "DOM/JDOM tree compare - internal error");
0683:                    }
0684:                    if (par1.isSameNodeInfo(par2)) {
0685:                        return ((SiblingCountingNode) p1).getSiblingPosition()
0686:                                - ((SiblingCountingNode) p2)
0687:                                        .getSiblingPosition();
0688:                    }
0689:                    p1 = par1;
0690:                    p2 = par2;
0691:                }
0692:            }
0693:
0694:            /**
0695:             * Classify node kinds into categories for sorting into document order:
0696:             * 0 = document, 1 = namespace, 2 = attribute, 3 = (element, text, comment, pi)
0697:             */
0698:
0699:            private static int[] nodeCategories = { -1, //0 = not used
0700:                    3, //1 = element
0701:                    2, //2 = attribute
0702:                    3, //3 = text
0703:                    -1, -1, -1, //4,5,6 = not used
0704:                    3, //7 = processing-instruction
0705:                    3, //8 = comment
0706:                    0, //9 = document
0707:                    -1, -1, -1, //10,11,12 = not used
0708:                    1 //13 = namespace
0709:            };
0710:
0711:            /**
0712:             * Get a character string that uniquely identifies this node and that collates nodes
0713:             * into document order
0714:             * @return a string. The string is always interned so keys can be compared using "==".
0715:             */
0716:
0717:            public static String getSequentialKey(SiblingCountingNode node) {
0718:                // This was designed so it could be used for sorting nodes into document
0719:                // order, but is not currently used that way.
0720:                StringBuffer key = new StringBuffer(12);
0721:                int num = node.getDocumentNumber();
0722:                while (node != null && node.getNodeKind() != Type.DOCUMENT) {
0723:                    key.insert(0, alphaKey(node.getSiblingPosition()));
0724:                    node = (SiblingCountingNode) node.getParent();
0725:                }
0726:                key.insert(0, "w" + num);
0727:                return key.toString().intern();
0728:            }
0729:
0730:            /**
0731:             * Construct an alphabetic key from an positive integer; the key collates in the same sequence
0732:             * as the integer
0733:             * @param value The positive integer key value (negative values are treated as zero).
0734:             */
0735:
0736:            public static String alphaKey(int value) {
0737:                if (value < 1)
0738:                    return "a";
0739:                if (value < 10)
0740:                    return "b" + value;
0741:                if (value < 100)
0742:                    return "c" + value;
0743:                if (value < 1000)
0744:                    return "d" + value;
0745:                if (value < 10000)
0746:                    return "e" + value;
0747:                if (value < 100000)
0748:                    return "f" + value;
0749:                if (value < 1000000)
0750:                    return "g" + value;
0751:                if (value < 10000000)
0752:                    return "h" + value;
0753:                if (value < 100000000)
0754:                    return "i" + value;
0755:                if (value < 1000000000)
0756:                    return "j" + value;
0757:                return "k" + value;
0758:            }
0759:
0760:            /**
0761:             * Determine if a string is all-whitespace
0762:             *
0763:             * @param content the string to be tested
0764:             * @return true if the supplied string contains no non-whitespace
0765:             *     characters
0766:             * @deprecated since Saxon 8.5: use {@link Whitespace#isWhite}
0767:             */
0768:
0769:            public static final boolean isWhite(CharSequence content) {
0770:                return Whitespace.isWhite(content);
0771:            }
0772:
0773:            ///////////////////////////////////////////////////////////////////////////////
0774:            // Helper classes to support axis iteration
0775:            ///////////////////////////////////////////////////////////////////////////////
0776:
0777:            /**
0778:             * AxisFilter is an iterator that applies a NodeTest filter to
0779:             * the nodes returned by an underlying AxisIterator.
0780:             */
0781:
0782:            public static class AxisFilter extends AxisIteratorImpl {
0783:                private AxisIterator base;
0784:                private NodeTest nodeTest;
0785:
0786:                //private int last = -1;
0787:
0788:                /**                             S
0789:                 * Construct a AxisFilter
0790:                 * @param base the underlying iterator that returns all the nodes on
0791:                 * a required axis. This must not be an atomizing iterator!
0792:                 * @param test a NodeTest that is applied to each node returned by the
0793:                 * underlying AxisIterator; only those nodes that pass the NodeTest are
0794:                 * returned by the AxisFilter
0795:                 */
0796:
0797:                public AxisFilter(AxisIterator base, NodeTest test) {
0798:                    this .base = base;
0799:                    this .nodeTest = test;
0800:                    position = 0;
0801:                }
0802:
0803:                public Item next() {
0804:                    while (true) {
0805:                        current = base.next();
0806:                        if (current == null) {
0807:                            position = -1;
0808:                            return null;
0809:                        }
0810:                        if (nodeTest.matches((NodeInfo) current)) {
0811:                            position++;
0812:                            return current;
0813:                        }
0814:                    }
0815:                }
0816:
0817:                public SequenceIterator getAnother() {
0818:                    return new AxisFilter((AxisIterator) base.getAnother(),
0819:                            nodeTest);
0820:                }
0821:            }
0822:
0823:            /**
0824:             * BaseEnumeration is an abstract implementation of an AxisIterator, it
0825:             * simplifies the implementation of the underlying AxisIterator by requiring
0826:             * it to provide only two methods: advance(), and getAnother().
0827:             *
0828:             * NOTA BENE: BaseEnumeration does not maintain the value of the position variable.
0829:             * It must therefore either (a) be wrapped in an AxisFilter, which does maintain
0830:             * position, or (b) be subclassed by a class that maintains position itself.
0831:             */
0832:
0833:            public static abstract class BaseEnumeration extends
0834:                    AxisIteratorImpl {
0835:
0836:                public final Item next() {
0837:                    advance();
0838:                    return current;
0839:                }
0840:
0841:                /**
0842:                 * The advance() method must be provided in each concrete implementation.
0843:                 * It must leave the variable current set to the next node to be returned in the
0844:                 * iteration, or to null if there are no more nodes to be returned.
0845:                 */
0846:
0847:                public abstract void advance();
0848:
0849:                public abstract SequenceIterator getAnother();
0850:
0851:            }
0852:
0853:            /**
0854:             * General-purpose implementation of the ancestor and ancestor-or-self axes
0855:             */
0856:
0857:            public static final class AncestorEnumeration extends
0858:                    BaseEnumeration {
0859:
0860:                private boolean includeSelf;
0861:                private boolean atStart;
0862:                private NodeInfo start;
0863:
0864:                public AncestorEnumeration(NodeInfo start, boolean includeSelf) {
0865:                    this .start = start;
0866:                    this .includeSelf = includeSelf;
0867:                    this .current = start;
0868:                    atStart = true;
0869:                }
0870:
0871:                public void advance() {
0872:                    if (atStart) {
0873:                        atStart = false;
0874:                        if (includeSelf) {
0875:                            return;
0876:                        }
0877:                    }
0878:                    current = ((NodeInfo) current).getParent();
0879:                }
0880:
0881:                public SequenceIterator getAnother() {
0882:                    return new AncestorEnumeration(start, includeSelf);
0883:                }
0884:
0885:            } // end of class AncestorEnumeration
0886:
0887:            /**
0888:             * General-purpose implementation of the descendant and descendant-or-self axes,
0889:             * in terms of the child axis.
0890:             * But it also has the option to return the descendants in reverse document order;
0891:             * this is used when evaluating the preceding axis. Note that the includeSelf option
0892:             * should not be used when scanning in reverse order, as the self node will always be
0893:             * returned first.
0894:             */
0895:
0896:            public static final class DescendantEnumeration extends
0897:                    BaseEnumeration {
0898:
0899:                private AxisIterator children = null;
0900:                private AxisIterator descendants = null;
0901:                private NodeInfo start;
0902:                private boolean includeSelf;
0903:                private boolean forwards;
0904:                private boolean atEnd = false;
0905:
0906:                public DescendantEnumeration(NodeInfo start,
0907:                        boolean includeSelf, boolean forwards) {
0908:                    this .start = start;
0909:                    this .includeSelf = includeSelf;
0910:                    this .forwards = forwards;
0911:                }
0912:
0913:                public void advance() {
0914:                    if (descendants != null) {
0915:                        Item nextd = descendants.next();
0916:                        if (nextd != null) {
0917:                            current = nextd;
0918:                            return;
0919:                        } else {
0920:                            descendants = null;
0921:                        }
0922:                    }
0923:                    if (children != null) {
0924:                        NodeInfo n = (NodeInfo) children.next();
0925:                        if (n != null) {
0926:                            if (n.hasChildNodes()) {
0927:                                if (forwards) {
0928:                                    descendants = new DescendantEnumeration(n,
0929:                                            false, forwards);
0930:                                    current = n;
0931:                                } else {
0932:                                    descendants = new DescendantEnumeration(n,
0933:                                            true, forwards);
0934:                                    advance();
0935:                                }
0936:                            } else {
0937:                                current = n;
0938:                            }
0939:                        } else {
0940:                            if (forwards || !includeSelf) {
0941:                                current = null;
0942:                            } else {
0943:                                atEnd = true;
0944:                                children = null;
0945:                                current = start;
0946:                            }
0947:                        }
0948:                    } else if (atEnd) {
0949:                        // we're just finishing a backwards scan
0950:                        current = null;
0951:                    } else {
0952:                        // we're just starting...
0953:                        if (start.hasChildNodes()) {
0954:                            //children = new NodeWrapper.ChildEnumeration(start, true, forwards);
0955:                            children = start.iterateAxis(Axis.CHILD);
0956:                            if (!forwards) {
0957:                                if (children instanceof  ReversibleIterator) {
0958:                                    children = (AxisIterator) ((ReversibleIterator) children)
0959:                                            .getReverseIterator();
0960:                                } else {
0961:                                    try {
0962:                                        children = new SequenceExtent(start
0963:                                                .iterateAxis(Axis.CHILD))
0964:                                                .reverseIterate();
0965:                                    } catch (XPathException e) {
0966:                                        throw new AssertionError(
0967:                                                "Internal error in Navigator#descendantEnumeration: "
0968:                                                        + e.getMessage());
0969:                                        // shouldn't happen.
0970:                                    }
0971:                                }
0972:                            }
0973:                        } else {
0974:                            children = EmptyIterator.getInstance();
0975:                        }
0976:                        if (forwards && includeSelf) {
0977:                            current = start;
0978:                        } else {
0979:                            advance();
0980:                        }
0981:                    }
0982:                }
0983:
0984:                public SequenceIterator getAnother() {
0985:                    return new DescendantEnumeration(start, includeSelf,
0986:                            forwards);
0987:                }
0988:
0989:            } // end of class DescendantEnumeration
0990:
0991:            /**
0992:             * General purpose implementation of the following axis, in terms of the
0993:             * ancestor, child, and following-sibling axes
0994:             */
0995:
0996:            public static final class FollowingEnumeration extends
0997:                    BaseEnumeration {
0998:                private NodeInfo start;
0999:                private AxisIterator ancestorEnum = null;
1000:                private AxisIterator siblingEnum = null;
1001:                private AxisIterator descendEnum = null;
1002:
1003:                public FollowingEnumeration(NodeInfo start) {
1004:                    this .start = start;
1005:                    ancestorEnum = new AncestorEnumeration(start, false);
1006:                    switch (start.getNodeKind()) {
1007:                    case Type.ELEMENT:
1008:                    case Type.TEXT:
1009:                    case Type.COMMENT:
1010:                    case Type.PROCESSING_INSTRUCTION:
1011:                        //siblingEnum = new NodeWrapper.ChildEnumeration(start, false, true);
1012:                        // gets following siblings
1013:                        siblingEnum = start.iterateAxis(Axis.FOLLOWING_SIBLING);
1014:                        break;
1015:                    case Type.ATTRIBUTE:
1016:                    case Type.NAMESPACE:
1017:                        //siblingEnum = new NodeWrapper.ChildEnumeration((NodeWrapper)start.getParent(), true, true);
1018:                        // gets children of the attribute's parent node
1019:                        NodeInfo parent = start.getParent();
1020:                        if (parent == null) {
1021:                            siblingEnum = EmptyIterator.getInstance();
1022:                        } else {
1023:                            siblingEnum = parent.iterateAxis(Axis.CHILD);
1024:                        }
1025:                        break;
1026:                    default:
1027:                        siblingEnum = EmptyIterator.getInstance();
1028:                    }
1029:                    //advance();
1030:                }
1031:
1032:                public void advance() {
1033:                    if (descendEnum != null) {
1034:                        Item nextd = descendEnum.next();
1035:                        if (nextd != null) {
1036:                            current = nextd;
1037:                            return;
1038:                        } else {
1039:                            descendEnum = null;
1040:                        }
1041:                    }
1042:                    if (siblingEnum != null) {
1043:                        Item nexts = siblingEnum.next();
1044:                        if (nexts != null) {
1045:                            current = nexts;
1046:                            NodeInfo n = (NodeInfo) current;
1047:                            if (n.hasChildNodes()) {
1048:                                descendEnum = new DescendantEnumeration(n,
1049:                                        false, true);
1050:                            } else {
1051:                                descendEnum = null;
1052:                            }
1053:                            return;
1054:                        } else {
1055:                            descendEnum = null;
1056:                            siblingEnum = null;
1057:                        }
1058:                    }
1059:                    Item nexta = ancestorEnum.next();
1060:                    if (nexta != null) {
1061:                        current = nexta;
1062:                        NodeInfo n = (NodeInfo) current;
1063:                        if (n.getNodeKind() == Type.DOCUMENT) {
1064:                            siblingEnum = EmptyIterator.getInstance();
1065:                        } else {
1066:                            //siblingEnum = new NodeWrapper.ChildEnumeration(next, false, true);
1067:                            siblingEnum = n.iterateAxis(Axis.FOLLOWING_SIBLING);
1068:                        }
1069:                        advance();
1070:                    } else {
1071:                        current = null;
1072:                    }
1073:                }
1074:
1075:                public SequenceIterator getAnother() {
1076:                    return new FollowingEnumeration(start);
1077:                }
1078:
1079:            } // end of class FollowingEnumeration
1080:
1081:            public static final class PrecedingEnumeration extends
1082:                    BaseEnumeration {
1083:
1084:                private NodeInfo start;
1085:                private AxisIterator ancestorEnum = null;
1086:                private AxisIterator siblingEnum = null;
1087:                private AxisIterator descendEnum = null;
1088:                private boolean includeAncestors;
1089:
1090:                public PrecedingEnumeration(NodeInfo start,
1091:                        boolean includeAncestors) {
1092:                    this .start = start;
1093:                    this .includeAncestors = includeAncestors;
1094:                    ancestorEnum = new AncestorEnumeration(start, false);
1095:                    switch (start.getNodeKind()) {
1096:                    case Type.ELEMENT:
1097:                    case Type.TEXT:
1098:                    case Type.COMMENT:
1099:                    case Type.PROCESSING_INSTRUCTION:
1100:                        // get preceding-sibling enumeration
1101:                        //siblingEnum = new NodeWrapper.ChildEnumeration(start, false, false);
1102:                        siblingEnum = start.iterateAxis(Axis.PRECEDING_SIBLING);
1103:                        break;
1104:                    default:
1105:                        siblingEnum = EmptyIterator.getInstance();
1106:                    }
1107:                    //advance();
1108:                }
1109:
1110:                public void advance() {
1111:                    if (descendEnum != null) {
1112:                        Item nextd = descendEnum.next();
1113:                        if (nextd != null) {
1114:                            current = nextd;
1115:                            return;
1116:                        } else {
1117:                            descendEnum = null;
1118:                        }
1119:                    }
1120:                    if (siblingEnum != null) {
1121:                        Item nexts = siblingEnum.next();
1122:                        if (nexts != null) {
1123:                            NodeInfo sib = (NodeInfo) nexts;
1124:                            if (sib.hasChildNodes()) {
1125:                                descendEnum = new DescendantEnumeration(sib,
1126:                                        true, false);
1127:                                advance();
1128:                            } else {
1129:                                descendEnum = null;
1130:                                current = sib;
1131:                            }
1132:                            return;
1133:                        } else {
1134:                            descendEnum = null;
1135:                            siblingEnum = null;
1136:                        }
1137:                    }
1138:                    Item nexta = ancestorEnum.next();
1139:                    if (nexta != null) {
1140:                        current = nexta;
1141:                        NodeInfo n = (NodeInfo) current;
1142:                        if (n.getNodeKind() == Type.DOCUMENT) {
1143:                            siblingEnum = EmptyIterator.getInstance();
1144:                        } else {
1145:                            siblingEnum = n.iterateAxis(Axis.PRECEDING_SIBLING);
1146:                        }
1147:                        if (!includeAncestors) {
1148:                            advance();
1149:                        }
1150:                    } else {
1151:                        current = null;
1152:                    }
1153:                }
1154:
1155:                public SequenceIterator getAnother() {
1156:                    return new PrecedingEnumeration(start, includeAncestors);
1157:                }
1158:
1159:            } // end of class PrecedingEnumeration
1160:
1161:        }
1162:
1163:        //
1164:        // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1165:        // you may not use this file except in compliance with the License. You may obtain a copy of the
1166:        // License at http://www.mozilla.org/MPL/
1167:        //
1168:        // Software distributed under the License is distributed on an "AS IS" basis,
1169:        // WITHOUT WARRANTY OF ANY KIND, either express or implied.
1170:        // See the License for the specific language governing rights and limitations under the License.
1171:        //
1172:        // The Original Code is: all this file.
1173:        //
1174:        // The Initial Developer of the Original Code is Michael H. Kay.
1175:        //
1176:        // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1177:        //
1178:        // Contributor(s): none.
1179:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.