001: package net.sf.saxon.pattern;
002:
003: import net.sf.saxon.om.Axis;
004: import net.sf.saxon.om.AxisIterator;
005: import net.sf.saxon.om.NodeInfo;
006: import net.sf.saxon.om.NamePool;
007: import net.sf.saxon.type.Type;
008: import net.sf.saxon.tinytree.TinyTree;
009:
010: /**
011: * A DocumentNodeTest implements the test document-node(element(~,~))
012: */
013:
014: // This is messy because the standard interface for a NodeTest does not allow
015: // any navigation from the node in question - it only tests for the node kind,
016: // node name, and type annotation of the node.
017: public class DocumentNodeTest extends NodeTest {
018:
019: private NodeTest elementTest;
020:
021: public DocumentNodeTest(NodeTest elementTest) {
022: this .elementTest = elementTest;
023: }
024:
025: /**
026: * Test whether this node test is satisfied by a given node
027: * @param nodeKind The type of node to be matched
028: * @param fingerprint identifies the expanded name of the node to be matched
029: */
030:
031: public boolean matches(int nodeKind, int fingerprint, int annotation) {
032: throw new UnsupportedOperationException(
033: "DocumentNodeTest doesn't support this method");
034: }
035:
036: /**
037: * Test whether this node test is satisfied by a given node on a TinyTree. The node
038: * must be a document, element, text, comment, or processing instruction node.
039: * This method is provided
040: * so that when navigating a TinyTree a node can be rejected without
041: * actually instantiating a NodeInfo object.
042: *
043: * @param tree the TinyTree containing the node
044: * @param nodeNr the number of the node within the TinyTree
045: * @return true if the node matches the NodeTest, otherwise false
046: */
047:
048: public boolean matches(TinyTree tree, int nodeNr) {
049: if (tree.getNodeKind(nodeNr) != Type.DOCUMENT) {
050: return false;
051: }
052: return matches(tree.getNode(nodeNr));
053: }
054:
055: /**
056: * Determine whether this Pattern matches the given Node.
057: * @param node The NodeInfo representing the Element or other node to be tested against the Pattern
058: * uses variables, or contains calls on functions such as document() or key().
059: * @return true if the node matches the Pattern, false otherwise
060: */
061:
062: public boolean matches(NodeInfo node) {
063: if (node.getNodeKind() != Type.DOCUMENT) {
064: return false;
065: }
066: AxisIterator iter = node.iterateAxis(Axis.CHILD);
067: // The match is true if there is exactly one element node child, no text node
068: // children, and the element node matches the element test.
069: boolean found = false;
070: while (true) {
071: NodeInfo n = (NodeInfo) iter.next();
072: if (n == null) {
073: return found;
074: }
075: int kind = n.getNodeKind();
076: if (kind == Type.TEXT) {
077: return false;
078: } else if (kind == Type.ELEMENT) {
079: if (found) {
080: return false;
081: }
082: if (elementTest.matches(n)) {
083: found = true;
084: } else {
085: return false;
086: }
087: }
088: }
089: }
090:
091: /**
092: * Determine the default priority of this node test when used on its own as a Pattern
093: */
094:
095: public final double getDefaultPriority() {
096: return elementTest.getDefaultPriority();
097: }
098:
099: /**
100: * Determine the types of nodes to which this pattern applies. Used for optimisation.
101: * @return the type of node matched by this pattern. e.g. Type.ELEMENT or Type.TEXT
102: */
103:
104: public int getPrimitiveType() {
105: return Type.DOCUMENT;
106: }
107:
108: /**
109: * Get a mask indicating which kinds of nodes this NodeTest can match. This is a combination
110: * of bits: 1<<Type.ELEMENT for element nodes, 1<<Type.TEXT for text nodes, and so on.
111: */
112:
113: public int getNodeKindMask() {
114: return 1 << Type.DOCUMENT;
115: }
116:
117: /**
118: * Get the element test contained within this document test
119: * @return the contained element test
120: */
121:
122: public NodeTest getElementTest() {
123: return elementTest;
124: }
125:
126: public String toString(NamePool pool) {
127: return "document-node(" + elementTest.toString(pool) + ')';
128: }
129:
130: public String toString() {
131: return "document-node(" + elementTest.toString() + ')';
132: }
133:
134: /**
135: * Returns a hash code value for the object.
136: */
137:
138: public int hashCode() {
139: return elementTest.hashCode() ^ 12345;
140: }
141:
142: public boolean equals(Object other) {
143: return other instanceof DocumentNodeTest
144: && ((DocumentNodeTest) other).elementTest
145: .equals(elementTest);
146: }
147:
148: }
149:
150: //
151: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
152: // you may not use this file except in compliance with the License. You may obtain a copy of the
153: // License at http://www.mozilla.org/MPL/
154: //
155: // Software distributed under the License is distributed on an "AS IS" basis,
156: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
157: // See the License for the specific language governing rights and limitations under the License.
158: //
159: // The Original Code is: all this file.
160: //
161: // The Initial Developer of the Original Code is Michael H. Kay.
162: //
163: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
164: //
165: // Contributor(s): none.
166: //
|