/** * @param result * @param expr */ private static void serialize( FastStringBuffer result, Expression expr, Map reversePrefixMapping) { if (expr instanceof Assignation) { // XXX not yet supported } else if (expr instanceof AxisExpression) { AxisExpression axisExpression = (AxisExpression) expr; result.append(Axis.axisName[axisExpression.getAxis()]); result.append("::"); final NodeTest nodeTest = axisExpression.getNodeTest(); if (nodeTest == null) { result.append("node()"); } else { result.append(fixPreFixes(nodeTest.toString(), reversePrefixMapping)); } } else if (expr instanceof BinaryExpression) { BinaryExpression binaryExpression = (BinaryExpression) expr; result.append('('); serialize(result, binaryExpression.getOperands()[0], reversePrefixMapping); result.append(Token.tokens[binaryExpression.getOperator()]); serialize(result, binaryExpression.getOperands()[1], reversePrefixMapping); result.append(')'); } else if (expr instanceof CompareToIntegerConstant) { CompareToIntegerConstant compareToIntegerConstant = (CompareToIntegerConstant) expr; result.append('('); serialize(result, compareToIntegerConstant.getOperand(), reversePrefixMapping); result.append(Token.tokens[compareToIntegerConstant.getComparisonOperator()]); result.append(Long.toString(compareToIntegerConstant.getComparand())); result.append(')'); } else if (expr instanceof ConditionalSorter) { // XXX not yet supported } else if (expr instanceof ContextItemExpression) { result.append('.'); } else if (expr instanceof ErrorExpression) { // Error do nothing } else if (expr instanceof FilterExpression) { FilterExpression filterExpression = (FilterExpression) expr; result.append('('); serialize(result, filterExpression.getControllingExpression(), reversePrefixMapping); result.append('['); serialize(result, filterExpression.getFilter(), reversePrefixMapping); result.append("])"); } else if (expr instanceof FunctionCall) { FunctionCall functionCall = (FunctionCall) expr; StructuredQName name = functionCall.getFunctionName(); if (name.getPrefix() != null && name.getPrefix().length() > 0) { result.append(name.getPrefix()); result.append(":"); } result.append(name.getLocalName()); result.append("("); Iterator iter = functionCall.iterateSubExpressions(); boolean first = true; while (iter.hasNext()) { result.append(first ? "" : ", "); SaxonXPathExpressionSerializer.serialize( result, (Expression) iter.next(), reversePrefixMapping); first = false; } result.append(")"); } else if (expr instanceof Instruction) { // This is not an XPath expression } else if (expr instanceof IntegerRangeTest) { // XXX not yet supported } else if (expr instanceof IsLastExpression) { result.append("position() eq last()"); } else if (expr instanceof Literal) { Literal literal = (Literal) expr; result.append(literal.getValue().toString()); } else if (expr instanceof NumberInstruction) { // This is not an XPath expression } else if (expr instanceof PathExpression) { PathExpression pathExpression = (PathExpression) expr; result.append('('); serialize(result, pathExpression.getControllingExpression(), reversePrefixMapping); result.append('/'); serialize(result, pathExpression.getControlledExpression(), reversePrefixMapping); result.append(')'); } else if (expr instanceof PatternMatchExpression) { // XXX not yet supported } else if (expr instanceof PatternSponsor) { // XXX not yet supported } else if (expr instanceof SimpleContentConstructor) { // This is not an XPath expression } else if (expr instanceof SimpleExpression) { // This is not an XPath expression } /* else if (expr instanceof SimpleMappingExpression) { // XXX not yet supported } */ else if (expr instanceof ParentNodeExpression) { result.append(".."); } else if (expr instanceof RootExpression) { // do nothing } else if (expr instanceof SortExpression) { // XXX not yet supported } else if (expr instanceof TailExpression) { // XXX not yet supported } else if (expr instanceof TupleExpression) { // This is not an XPath expression } else if (expr instanceof TupleSorter) { // This is not an XPath expression } else if (expr instanceof UnaryExpression) { UnaryExpression unaryExpression = (UnaryExpression) expr; serialize( result, unaryExpression.getBaseExpression(), reversePrefixMapping); // Not sure if this is correct in all cases } else if (expr instanceof VariableReference) { VariableReference variableReference = (VariableReference) expr; String d = variableReference.getDisplayName(); result.append("$"); result.append(d == null ? "$" : d); } }
/** Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Configuration config = visitor.getConfiguration(); NamePool namePool = config.getNamePool(); StaticContext env = visitor.getStaticContext(); if (contextItemType == null) { typeError( visitor, "Axis step " + toString(namePool) + " cannot be used here: the context item is undefined", "XPDY0002", null); } if (contextItemType.isAtomicType()) { typeError( visitor, "Axis step " + toString(namePool) + " cannot be used here: the context item is an atomic value", "XPTY0020", null); } if (this.contextItemType == contextItemType && doneWarnings) { return this; } this.contextItemType = contextItemType; doneWarnings = true; if (contextItemType instanceof NodeTest) { int origin = contextItemType.getPrimitiveType(); if (origin != Type.NODE) { if (Axis.isAlwaysEmpty(axis, origin)) { env.issueWarning( "The " + Axis.axisName[axis] + " axis starting at " + (origin == Type.ELEMENT || origin == Type.ATTRIBUTE ? "an " : "a ") + NodeKindTest.nodeKindName(origin) + " node will never select anything", getSourceLocator()); return Literal.makeEmptySequence(); } } if (test != null) { int kind = test.getPrimitiveType(); if (kind != Type.NODE) { if (!Axis.containsNodeKind(axis, kind)) { env.issueWarning( "The " + Axis.axisName[axis] + " axis will never select any " + NodeKindTest.nodeKindName(kind) + " nodes", getSourceLocator()); return Literal.makeEmptySequence(); } } if (axis == Axis.SELF && kind != Type.NODE && origin != Type.NODE && kind != origin) { env.issueWarning( "The self axis will never select any " + NodeKindTest.nodeKindName(kind) + " nodes when starting at " + (origin == Type.ELEMENT || origin == Type.ATTRIBUTE ? "an " : "a ") + NodeKindTest.nodeKindName(origin) + " node", getSourceLocator()); return Literal.makeEmptySequence(); } if (axis == Axis.SELF) { itemType = new CombinedNodeTest(test, Token.INTERSECT, (NodeTest) contextItemType); } // If the content type of the context item is known, see whether the node test can select // anything if (contextItemType instanceof DocumentNodeTest && kind == Type.ELEMENT) { NodeTest elementTest = ((DocumentNodeTest) contextItemType).getElementTest(); Set<Integer> outermostElementNames = elementTest.getRequiredNodeNames(); if (outermostElementNames != null) { Set<Integer> selectedElementNames = test.getRequiredNodeNames(); if (selectedElementNames != null) { if (axis == Axis.CHILD) { // check that the name appearing in the step is one of the names allowed by the // nodetest if (SetUtils.intersect(selectedElementNames, outermostElementNames).isEmpty()) { env.issueWarning( "Starting at a document node, the step is selecting an element whose name " + "is not among the names of child elements permitted for this document node type", getSourceLocator()); return Literal.makeEmptySequence(); } itemType = elementTest; return this; } else if (axis == Axis.DESCENDANT) { // check that the name appearing in the step is one of the names allowed by the // nodetest boolean canMatchOutermost = !SetUtils.intersect(selectedElementNames, outermostElementNames).isEmpty(); if (!canMatchOutermost) { // The expression /descendant::x starting at the document node doesn't match the // outermost // element, so replace it by child::*/descendant::x, and check that PathExpression path = new PathExpression( new AxisExpression(Axis.CHILD, elementTest), new AxisExpression(Axis.DESCENDANT, test)); ExpressionTool.copyLocationInfo(this, path); return path.typeCheck(visitor, contextItemType); } } } } } } } return this; }