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


001:        package net.sf.saxon.expr;
002:
003:        import net.sf.saxon.om.Axis;
004:        import net.sf.saxon.om.Item;
005:        import net.sf.saxon.om.NamePool;
006:        import net.sf.saxon.om.SequenceIterator;
007:        import net.sf.saxon.pattern.AnyNodeTest;
008:        import net.sf.saxon.pattern.NodeKindTest;
009:        import net.sf.saxon.pattern.NodeTest;
010:        import net.sf.saxon.sort.DocumentSorter;
011:        import net.sf.saxon.sort.Reverser;
012:        import net.sf.saxon.trace.Location;
013:        import net.sf.saxon.trans.XPathException;
014:        import net.sf.saxon.type.ItemType;
015:        import net.sf.saxon.type.Type;
016:        import net.sf.saxon.type.TypeHierarchy;
017:        import net.sf.saxon.value.Cardinality;
018:        import net.sf.saxon.value.EmptySequence;
019:        import net.sf.saxon.value.SequenceType;
020:
021:        import java.io.PrintStream;
022:        import java.util.Iterator;
023:
024:        /**
025:         * An expression that establishes a set of nodes by following relationships between nodes
026:         * in the document. Specifically, it consists of a start expression which defines a set of
027:         * nodes, and a Step which defines a relationship to be followed from those nodes to create
028:         * a new set of nodes.
029:         */
030:
031:        public final class PathExpression extends ComputedExpression implements 
032:                MappingFunction {
033:
034:            private Expression start;
035:            private Expression step;
036:            private transient int state = 0; // 0 = raw, 1 = simplified, 2 = analyzed, 3 = optimized
037:
038:            /**
039:             * Constructor
040:             * @param start A node-set expression denoting the absolute or relative set of nodes from which the
041:             * navigation path should start.
042:             * @param step The step to be followed from each node in the start expression to yield a new
043:             * node-set
044:             */
045:
046:            public PathExpression(Expression start, Expression step) {
047:                this .start = start;
048:                this .step = step;
049:                adoptChildExpression(start);
050:                adoptChildExpression(step);
051:
052:                // If start is a path expression such as a, and step is b/c, then
053:                // instead of a/(b/c) we construct (a/b)/c. This is because it often avoids
054:                // a sort.
055:
056:                // The "/" operator in XPath 2.0 is not always associative. Problems
057:                // can occur if position() and last() are used on the rhs, or if node-constructors
058:                // appear, e.g. //b/../<d/>. So we only do this rewrite if the step is a path
059:                // expression in which both operands are axis expressions optionally with predicates
060:
061:                if (step instanceof  PathExpression) {
062:                    PathExpression stepPath = (PathExpression) step;
063:                    if (isFilteredAxisPath(stepPath.start)
064:                            && isFilteredAxisPath(stepPath.step)) {
065:                        this .start = new PathExpression(start, stepPath.start);
066:                        ExpressionTool.copyLocationInfo(start, this .start);
067:                        this .step = stepPath.step;
068:                        resetStaticProperties();
069:                    }
070:                }
071:            }
072:
073:            /**
074:             * Get the start expression (the left-hand operand)
075:             */
076:
077:            public Expression getStartExpression() {
078:                return start;
079:            }
080:
081:            /**
082:             * Get the step expression (the right-hand operand)
083:             */
084:
085:            public Expression getStepExpression() {
086:                return step;
087:            }
088:
089:            /**
090:             * Determine whether an operand of a PathExpression is an
091:             * axis step with optional filter predicates.
092:             */
093:
094:            private static boolean isFilteredAxisPath(Expression exp) {
095:                if (exp instanceof  AxisExpression) {
096:                    return true;
097:                } else {
098:                    while (exp instanceof  FilterExpression) {
099:                        exp = ((FilterExpression) exp).getBaseExpression();
100:                    }
101:                    return exp instanceof  AxisExpression;
102:                }
103:            }
104:
105:            /**
106:             * Determine the data type of the items returned by this exprssion
107:             * @return the type of the step
108:             * @param th
109:             */
110:
111:            public final ItemType getItemType(TypeHierarchy th) {
112:                return step.getItemType(th);
113:            }
114:
115:            /**
116:             * Simplify an expression
117:             * @return the simplified expression
118:             */
119:
120:            public Expression simplify(StaticContext env) throws XPathException {
121:                if (state > 0)
122:                    return this ;
123:                state = 1;
124:                start = start.simplify(env);
125:                step = step.simplify(env);
126:                resetStaticProperties();
127:
128:                // if the start expression is an empty sequence, then the whole PathExpression is empty
129:                if (start instanceof  EmptySequence) {
130:                    return start;
131:                }
132:
133:                // if the simplified Step is an empty sequence, then the whole PathExpression is empty
134:                if (step instanceof  EmptySequence) {
135:                    return step;
136:                }
137:
138:                // Remove a redundant "." from the path
139:                // Note: we are careful not to do this unless the other operand is an ordered node-set.
140:                // In other cases, ./E (or E/.) is not a no-op, because it forces sorting.
141:
142:                if (start instanceof  ContextItemExpression) {
143:                    if (step instanceof  PathExpression
144:                            || (step.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) {
145:                        return step;
146:                    }
147:                }
148:
149:                if (step instanceof  ContextItemExpression
150:                        && (start instanceof  PathExpression || (start
151:                                .getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0)) {
152:                    return start;
153:                }
154:
155:                // Remove a redundant "." in the middle of a path expression
156:
157:                if (step instanceof  PathExpression
158:                        && ((PathExpression) step).getFirstStep() instanceof  ContextItemExpression) {
159:                    return new PathExpression(start, ((PathExpression) step)
160:                            .getRemainingSteps());
161:                }
162:
163:                if (start instanceof  PathExpression
164:                        && ((PathExpression) start).getLastStep() instanceof  ContextItemExpression) {
165:                    return new PathExpression(((PathExpression) start)
166:                            .getLeadingSteps(), step);
167:                }
168:
169:                // the expression /.. is sometimes used to represent the empty node-set
170:
171:                if (start instanceof  RootExpression
172:                        && step instanceof  ParentNodeExpression) {
173:                    return EmptySequence.getInstance();
174:                }
175:
176:                return this ;
177:            }
178:
179:            // Simplify an expression of the form a//b, where b has no positional filters.
180:            // This comes out of the contructor above as (a/descendent-or-self::node())/child::b,
181:            // but it is equivalent to a/descendant::b; and the latter is better as it
182:            // doesn't require sorting. Note that we can't do this until type information is available,
183:            // as we need to know whether any filters are positional or not.
184:
185:            private PathExpression simplifyDescendantPath(StaticContext env)
186:                    throws XPathException {
187:
188:                Expression st = start;
189:
190:                // detect .//x as a special case; this will appear as descendant-or-self::node()/x
191:
192:                if (start instanceof  AxisExpression) {
193:                    AxisExpression stax = (AxisExpression) start;
194:                    if (stax.getAxis() != Axis.DESCENDANT_OR_SELF) {
195:                        return null;
196:                    }
197:                    ContextItemExpression cie = new ContextItemExpression();
198:                    ExpressionTool.copyLocationInfo(this , cie);
199:                    st = new PathExpression(cie, stax);
200:                    ExpressionTool.copyLocationInfo(this , st);
201:                }
202:
203:                if (!(st instanceof  PathExpression)) {
204:                    return null;
205:                }
206:
207:                PathExpression startPath = (PathExpression) st;
208:                if (!(startPath.step instanceof  AxisExpression)) {
209:                    return null;
210:                }
211:
212:                AxisExpression mid = (AxisExpression) startPath.step;
213:                if (mid.getAxis() != Axis.DESCENDANT_OR_SELF) {
214:                    return null;
215:                }
216:
217:                NodeTest test = mid.getNodeTest();
218:                if (!(test == null || test instanceof  AnyNodeTest)) {
219:                    return null;
220:                }
221:
222:                Expression underlyingStep = step;
223:                while (underlyingStep instanceof  FilterExpression) {
224:                    if (((FilterExpression) underlyingStep).isPositional(env
225:                            .getNamePool().getTypeHierarchy())) {
226:                        return null;
227:                    }
228:                    underlyingStep = ((FilterExpression) underlyingStep)
229:                            .getBaseExpression();
230:                }
231:
232:                if (!(underlyingStep instanceof  AxisExpression)) {
233:                    return null;
234:                }
235:
236:                AxisExpression underlyingAxis = (AxisExpression) underlyingStep;
237:                if (underlyingAxis.getAxis() == Axis.CHILD) {
238:
239:                    ComputedExpression newStep = new AxisExpression(
240:                            Axis.DESCENDANT, ((AxisExpression) underlyingStep)
241:                                    .getNodeTest());
242:                    ExpressionTool.copyLocationInfo(this , newStep);
243:
244:                    underlyingStep = step;
245:                    while (underlyingStep instanceof  FilterExpression) {
246:                        // Add any filters to the new expression. We know they aren't
247:                        // positional, so the order of the filters doesn't matter.
248:                        newStep = new FilterExpression(
249:                                newStep,
250:                                ((FilterExpression) underlyingStep).getFilter(),
251:                                env);
252:                        ExpressionTool
253:                                .copyLocationInfo(underlyingStep, newStep);
254:                        underlyingStep = ((FilterExpression) underlyingStep)
255:                                .getBaseExpression();
256:                    }
257:
258:                    //System.err.println("Simplified this:");
259:                    //    display(10);
260:                    //System.err.println("as this:");
261:                    //    new PathExpression(startPath.start, newStep).display(10);
262:
263:                    PathExpression newPath = new PathExpression(
264:                            startPath.start, newStep);
265:                    ExpressionTool.copyLocationInfo(this , newPath);
266:                    return newPath;
267:                }
268:
269:                if (underlyingAxis.getAxis() == Axis.ATTRIBUTE) {
270:
271:                    // turn the expression a//@b into a/descendant-or-self::*/@b
272:
273:                    ComputedExpression newStep = new AxisExpression(
274:                            Axis.DESCENDANT_OR_SELF, NodeKindTest.ELEMENT);
275:                    ExpressionTool.copyLocationInfo(this , newStep);
276:
277:                    PathExpression newPath = new PathExpression(
278:                            new PathExpression(startPath.start, newStep), step);
279:                    ExpressionTool.copyLocationInfo(this , newPath);
280:                    return newPath;
281:                }
282:
283:                return null;
284:            }
285:
286:            /**
287:             * Optimize the expression and perform type analysis
288:             */
289:
290:            public Expression typeCheck(StaticContext env,
291:                    ItemType contextItemType) throws XPathException {
292:
293:                final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
294:                if (state >= 2) {
295:                    // we've already done the main analysis, and we don't want to do it again because
296:                    // decisions on sorting get upset. But we have new information, namely the contextItemType,
297:                    // so we use that to check that it's a node
298:                    Expression start2 = start.typeCheck(env, contextItemType);
299:                    if (start2 != start) {
300:                        adoptChildExpression(start2);
301:                        start = start2;
302:                    }
303:                    Expression step2 = step.typeCheck(env, start
304:                            .getItemType(th));
305:                    if (step2 != step) {
306:                        adoptChildExpression(step2);
307:                        step = step2;
308:                    }
309:                    return this ;
310:                }
311:                ;
312:                state = 2;
313:
314:                Expression start2 = start.typeCheck(env, contextItemType);
315:                if (start2 != start) {
316:                    adoptChildExpression(start2);
317:                    start = start2;
318:                }
319:
320:                // The first operand must be of type node()*
321:
322:                RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR,
323:                        "/", 0, null);
324:                role0.setSourceLocator(this );
325:                role0.setErrorCode("XPTY0019");
326:                start2 = TypeChecker.staticTypeCheck(start,
327:                        SequenceType.NODE_SEQUENCE, false, role0, env);
328:                if (start2 != start) {
329:                    adoptChildExpression(start2);
330:                    start = start2;
331:                }
332:
333:                // Now check the second operand
334:
335:                Expression step2 = step.typeCheck(env, start.getItemType(th));
336:                if (step2 != step) {
337:                    adoptChildExpression(step2);
338:                    step = step2;
339:                }
340:
341:                // We distinguish three cases for the second operand: either it is known statically to deliver
342:                // nodes only (a traditional path expression), or it is known statically to deliver atomic values
343:                // only (a simple mapping expression), or we don't yet know.
344:
345:                ItemType stepType = step.getItemType(th);
346:                if (th.isSubType(stepType, Type.NODE_TYPE)) {
347:
348:                    if ((step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) {
349:
350:                        // A traditional path expression
351:
352:                        // We don't need the operands to be sorted; any sorting that's needed
353:                        // will be done at the top level
354:
355:                        Optimizer opt = env.getConfiguration().getOptimizer();
356:                        start2 = ExpressionTool.unsorted(opt, start, false);
357:                        if (start2 != start) {
358:                            resetStaticProperties();
359:                            adoptChildExpression(start2);
360:                            start = start2;
361:                        }
362:                        step2 = ExpressionTool.unsorted(opt, step, false);
363:                        if (step2 != step) {
364:                            resetStaticProperties();
365:                            adoptChildExpression(step2);
366:                            step = step2;
367:                        }
368:
369:                        // Try to simplify expressions such as a//b
370:                        PathExpression p = simplifyDescendantPath(env);
371:                        if (p != null) {
372:                            p.setParentExpression(getParentExpression());
373:                            return p.simplify(env).typeCheck(env,
374:                                    contextItemType);
375:                        }
376:                    }
377:
378:                    // Decide whether the result needs to be wrapped in a sorting
379:                    // expression to deliver the results in document order
380:
381:                    int props = getSpecialProperties();
382:
383:                    if ((props & StaticProperty.ORDERED_NODESET) != 0) {
384:                        return this ;
385:                    } else if ((props & StaticProperty.REVERSE_DOCUMENT_ORDER) != 0) {
386:                        return new Reverser(this );
387:                    } else {
388:                        return new DocumentSorter(this );
389:                    }
390:
391:                } else if (stepType.isAtomicType()) {
392:                    // This is a simple mapping expression: a/b where b returns atomic values
393:                    return new SimpleMappingExpression(start, step, false)
394:                            .simplify(env).typeCheck(env, contextItemType);
395:                } else {
396:                    // This is a hybrid mapping expression, one where we don't know the type of the step
397:                    // (and therefore, we don't know whether sorting into document order is required) until run-time
398:                    return new SimpleMappingExpression(start, step, true)
399:                            .simplify(env).typeCheck(env, contextItemType);
400:                }
401:            }
402:
403:            /**
404:             * Optimize the expression and perform type analysis
405:             */
406:
407:            public Expression optimize(Optimizer opt, StaticContext env,
408:                    ItemType contextItemType) throws XPathException {
409:
410:                final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
411:                if (state >= 3) {
412:                    // we've already done the main analysis, and we don't want to do it again because
413:                    // decisions on sorting get upset. But we have new information, namely the contextItemType,
414:                    // so we use that to check that it's a node
415:                    Expression start2 = start.optimize(opt, env,
416:                            contextItemType);
417:                    if (start2 != start) {
418:                        adoptChildExpression(start2);
419:                        start = start2;
420:                    }
421:                    Expression step2 = step.optimize(opt, env, start
422:                            .getItemType(th));
423:                    if (step2 != step) {
424:                        adoptChildExpression(step2);
425:                        step = step2;
426:                    }
427:                    return this ;
428:                }
429:                ;
430:                state = 3;
431:
432:                Expression k = opt.convertPathExpressionToKey(this , env);
433:                if (k != null) {
434:                    return k;
435:                }
436:
437:                Expression start2 = start.optimize(opt, env, contextItemType);
438:                if (start2 != start) {
439:                    adoptChildExpression(start2);
440:                    start = start2;
441:                }
442:                Expression step2 = step.optimize(opt, env, start
443:                        .getItemType(th));
444:                if (step2 != step) {
445:                    adoptChildExpression(step2);
446:                    step = step2;
447:                }
448:
449:                // If any subexpressions within the step are not dependent on the focus,
450:                // and if they are not "creative" expressions (expressions that can create new nodes), then
451:                // promote them: this causes them to be evaluated once, outside the path expression
452:
453:                PromotionOffer offer = new PromotionOffer(opt);
454:                offer.action = PromotionOffer.FOCUS_INDEPENDENT;
455:                offer.promoteDocumentDependent = (start.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0;
456:                offer.containingExpression = this ;
457:
458:                step = doPromotion(step, offer);
459:                resetStaticProperties();
460:                if (offer.containingExpression != this ) {
461:                    state = 0; // allow reanalysis (see test axes286)
462:                    offer.containingExpression = offer.containingExpression
463:                            .typeCheck(env, contextItemType).optimize(opt, env,
464:                                    contextItemType);
465:                    return offer.containingExpression;
466:                }
467:                return this ;
468:
469:            }
470:
471:            /**
472:             * Promote this expression if possible
473:             */
474:
475:            public Expression promote(PromotionOffer offer)
476:                    throws XPathException {
477:                Expression p = this ;
478:                if (offer.action == PromotionOffer.RANGE_INDEPENDENT) {
479:                    // try converting the expression first from a/b/c[pred] to (a/b/c)[pred] so that a/b/c can be promoted
480:
481:                    final Optimizer optimizer = offer.getOptimizer();
482:                    FilterExpression p2 = optimizer.convertToFilterExpression(
483:                            this , optimizer.getConfiguration().getNamePool()
484:                                    .getTypeHierarchy());
485:                    if (p2 != null) {
486:                        return p2.promote(offer);
487:                    }
488:                }
489:                Expression exp = offer.accept(p);
490:                if (exp != null) {
491:                    return exp;
492:                } else {
493:                    start = doPromotion(start, offer);
494:                    if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES
495:                            || offer.action == PromotionOffer.REPLACE_CURRENT) {
496:                        // Don't pass on other requests. We could pass them on, but only after augmenting
497:                        // them to say we are interested in subexpressions that don't depend on either the
498:                        // outer context or the inner context.
499:                        step = doPromotion(step, offer);
500:                    }
501:                    return this ;
502:                }
503:            }
504:
505:            /**
506:             * Get the immediate subexpressions of this expression
507:             */
508:
509:            public Iterator iterateSubExpressions() {
510:                return new PairIterator(start, step);
511:            }
512:
513:            /**
514:             * Determine which aspects of the context the expression depends on. The result is
515:             * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and
516:             * XPathContext.CURRENT_NODE
517:             */
518:
519:            public int computeDependencies() {
520:                return start.getDependencies() |
521:                // not all dependencies in the step matter, because the context node, etc,
522:                        // are not those of the outer expression
523:                        (step.getDependencies() & (StaticProperty.DEPENDS_ON_XSLT_CONTEXT
524:                                | StaticProperty.DEPENDS_ON_LOCAL_VARIABLES | StaticProperty.DEPENDS_ON_USER_FUNCTIONS));
525:            }
526:
527:            /**
528:             * Get the static properties of this expression (other than its type). The result is
529:             * bit-signficant. These properties are used for optimizations. In general, if
530:             * property bit is set, it is true, but if it is unset, the value is unknown.
531:             */
532:
533:            public int computeSpecialProperties() {
534:                int startProperties = start.getSpecialProperties();
535:                int stepProperties = step.getSpecialProperties();
536:
537:                int p = 0;
538:                if (!Cardinality.allowsMany(start.getCardinality())) {
539:                    startProperties |= StaticProperty.ORDERED_NODESET
540:                            | StaticProperty.PEER_NODESET;
541:                }
542:                if (!Cardinality.allowsMany(step.getCardinality())) {
543:                    stepProperties |= StaticProperty.ORDERED_NODESET
544:                            | StaticProperty.PEER_NODESET;
545:                }
546:
547:                if ((startProperties & stepProperties & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) {
548:                    p |= StaticProperty.CONTEXT_DOCUMENT_NODESET;
549:                }
550:                if (((startProperties & StaticProperty.SINGLE_DOCUMENT_NODESET) != 0)
551:                        && ((stepProperties & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0)) {
552:                    p |= StaticProperty.SINGLE_DOCUMENT_NODESET;
553:                }
554:                if ((startProperties & stepProperties & StaticProperty.PEER_NODESET) != 0) {
555:                    p |= StaticProperty.PEER_NODESET;
556:                }
557:                if ((startProperties & stepProperties & StaticProperty.SUBTREE_NODESET) != 0) {
558:                    p |= StaticProperty.SUBTREE_NODESET;
559:                }
560:
561:                if (testNaturallySorted(startProperties, stepProperties)) {
562:                    p |= StaticProperty.ORDERED_NODESET;
563:                }
564:
565:                if (testNaturallyReverseSorted()) {
566:                    p |= StaticProperty.REVERSE_DOCUMENT_ORDER;
567:                }
568:
569:                if ((startProperties & stepProperties & StaticProperty.NON_CREATIVE) != 0) {
570:                    p |= StaticProperty.NON_CREATIVE;
571:                }
572:
573:                return p;
574:            }
575:
576:            /**
577:             * Determine if we can guarantee that the nodes are delivered in document order.
578:             * This is true if the start nodes are sorted peer nodes
579:             * and the step is based on an Axis within the subtree rooted at each node.
580:             * It is also true if the start is a singleton node and the axis is sorted.
581:             */
582:
583:            private boolean testNaturallySorted(int startProperties,
584:                    int stepProperties) {
585:
586:                // System.err.println("**** Testing pathExpression.isNaturallySorted()");
587:                // display(20);
588:                // System.err.println("Start is ordered node-set? " + start.isOrderedNodeSet());
589:                // System.err.println("Start is naturally sorted? " + start.isNaturallySorted());
590:                // System.err.println("Start is singleton? " + start.isSingleton());
591:
592:                if ((stepProperties & StaticProperty.ORDERED_NODESET) == 0) {
593:                    return false;
594:                }
595:                if (Cardinality.allowsMany(start.getCardinality())) {
596:                    if ((startProperties & StaticProperty.ORDERED_NODESET) == 0) {
597:                        return false;
598:                    }
599:                } else {
600:                    //if ((stepProperties & StaticProperty.ORDERED_NODESET) != 0) {
601:                    return true;
602:                    //}
603:                }
604:
605:                // We know now that both the start and the step are sorted. But this does
606:                // not necessarily mean that the combination is sorted.
607:
608:                // The result is sorted if the start is sorted and the step selects attributes
609:                // or namespaces
610:
611:                if ((stepProperties & StaticProperty.ATTRIBUTE_NS_NODESET) != 0) {
612:                    return true;
613:                }
614:
615:                // The result is sorted if the start selects "peer nodes" (that is, a node-set in which
616:                // no node is an ancestor of another) and the step selects within the subtree rooted
617:                // at the context node
618:
619:                if (((startProperties & StaticProperty.PEER_NODESET) != 0)
620:                        && ((stepProperties & StaticProperty.SUBTREE_NODESET) != 0)) {
621:                    return true;
622:                }
623:
624:                return false;
625:            }
626:
627:            /**
628:             * Determine if the path expression naturally returns nodes in reverse document order
629:             */
630:
631:            private boolean testNaturallyReverseSorted() {
632:
633:                // Some examples of expressions that are naturally reverse sorted:
634:                //     ../@x
635:                //     ancestor::*[@lang]
636:                //     ../preceding-sibling::x
637:                //     $x[1]/preceding-sibling::node()
638:
639:                // This information is used to do a simple reversal of the nodes
640:                // instead of a full sort, which is significantly cheaper, especially
641:                // when using tree models (such as DOM and JDOM) in which comparing
642:                // nodes in document order is an expensive operation.
643:
644:                if (!Cardinality.allowsMany(start.getCardinality())
645:                        && (step instanceof  AxisExpression)) {
646:                    return !Axis.isForwards[((AxisExpression) step).getAxis()];
647:                }
648:
649:                if (!(start instanceof  AxisExpression)) {
650:                    return false;
651:                }
652:
653:                if (Axis.isForwards[((AxisExpression) start).getAxis()]) {
654:                    return false;
655:                }
656:
657:                //        if (step instanceof AttributeReference) {
658:                //            return true;
659:                //        }
660:
661:                return false;
662:            }
663:
664:            /**
665:             * Determine the static cardinality of the expression
666:             */
667:
668:            public int computeCardinality() {
669:                int c1 = start.getCardinality();
670:                int c2 = step.getCardinality();
671:                return Cardinality.multiply(c1, c2);
672:            }
673:
674:            /**
675:             * Is this expression the same as another expression?
676:             */
677:
678:            public boolean equals(Object other) {
679:                if (!(other instanceof  PathExpression)) {
680:                    return false;
681:                }
682:                PathExpression p = (PathExpression) other;
683:                return (start.equals(p.start) && step.equals(p.step));
684:            }
685:
686:            /**
687:             * get HashCode for comparing two expressions
688:             */
689:
690:            public int hashCode() {
691:                return "PathExpression".hashCode() + start.hashCode()
692:                        + step.hashCode();
693:            }
694:
695:            /**
696:             * Get the first step in this expression. A path expression A/B/C is represented as (A/B)/C, but
697:             * the first step is A
698:             */
699:
700:            public Expression getFirstStep() {
701:                if (start instanceof  PathExpression) {
702:                    return ((PathExpression) start).getFirstStep();
703:                } else {
704:                    return start;
705:                }
706:            }
707:
708:            /**
709:             * Get all steps after the first.
710:             * This is complicated by the fact that A/B/C is represented as ((A/B)/C; we are required
711:             * to return B/C
712:             */
713:
714:            public Expression getRemainingSteps() {
715:                if (start instanceof  PathExpression) {
716:                    PathExpression rem = new PathExpression(
717:                            ((PathExpression) start).getRemainingSteps(), step);
718:                    rem.setParentExpression(getParentExpression());
719:                    ExpressionTool.copyLocationInfo(start, rem);
720:                    return rem;
721:                } else {
722:                    return step;
723:                }
724:            }
725:
726:            /**
727:             * Get the last step of the path expression
728:             */
729:
730:            public Expression getLastStep() {
731:                if (step instanceof  PathExpression) {
732:                    return ((PathExpression) step).getLastStep();
733:                } else {
734:                    return step;
735:                }
736:            }
737:
738:            /**
739:             * Get a path expression consisting of all steps except the last
740:             */
741:
742:            public Expression getLeadingSteps() {
743:                if (step instanceof  PathExpression) {
744:                    PathExpression rem = new PathExpression(start,
745:                            ((PathExpression) step).getLeadingSteps());
746:                    ExpressionTool.copyLocationInfo(start, rem);
747:                    return rem;
748:                } else {
749:                    return start;
750:                }
751:            }
752:
753:            /**
754:             * Test whether a path expression is an absolute path - that is, a path whose first step selects a
755:             * document node
756:             */
757:
758:            public boolean isAbsolute(TypeHierarchy th) {
759:                return getFirstStep().getItemType(th).getPrimitiveType() == Type.DOCUMENT;
760:            }
761:
762:            /**
763:             * Iterate the path-expression in a given context
764:             * @param context the evaluation context
765:             */
766:
767:            public SequenceIterator iterate(XPathContext context)
768:                    throws XPathException {
769:
770:                // This class delivers the result of the path expression in unsorted order,
771:                // without removal of duplicates. If sorting and deduplication are needed,
772:                // this is achieved by wrapping the path expression in a DocumentSorter
773:
774:                SequenceIterator master = start.iterate(context);
775:                XPathContext context2 = context.newMinorContext();
776:                context2.setCurrentIterator(master);
777:                context2.setOriginatingConstructType(Location.PATH_EXPRESSION);
778:
779:                master = new MappingIterator(master, this , context2);
780:                return master;
781:
782:            }
783:
784:            /**
785:             * Mapping function, from a node returned by the start iteration, to a sequence
786:             * returned by the child.
787:             */
788:
789:            public Object map(Item item, XPathContext context)
790:                    throws XPathException {
791:                return step.iterate(context);
792:            }
793:
794:            /**
795:             * Diagnostic print of expression structure
796:             */
797:
798:            public void display(int level, NamePool pool, PrintStream out) {
799:                out.println(ExpressionTool.indent(level) + "path /");
800:                start.display(level + 1, pool, out);
801:                step.display(level + 1, pool, out);
802:            }
803:
804:        }
805:
806:        //
807:        // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
808:        // you may not use this file except in compliance with the License. You may obtain a copy of the
809:        // License at http://www.mozilla.org/MPL/
810:        //
811:        // Software distributed under the License is distributed on an "AS IS" basis,
812:        // WITHOUT WARRANTY OF ANY KIND, either express or implied.
813:        // See the License for the specific language governing rights and limitations under the License.
814:        //
815:        // The Original Code is: all this file.
816:        //
817:        // The Initial Developer of the Original Code is Michael H. Kay.
818:        //
819:        // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
820:        //
821:        // Contributor(s): none.
822:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.