001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.xpath.pattern;
030:
031: import com.caucho.xpath.ExprEnvironment;
032: import com.caucho.xpath.XPathException;
033:
034: import org.w3c.dom.Document;
035: import org.w3c.dom.Node;
036:
037: /**
038: * Matches a node without checking the name. e.g. * or @*
039: */
040: public class NodeTypePattern extends AbstractPattern {
041: public final static int NODE = -2;
042: public final static int ANY = -1;
043:
044: private AbstractPattern _match;
045: private int _nodeType;
046:
047: private NodeTypePattern(AbstractPattern parent, int nodeType) {
048: super (parent);
049:
050: _nodeType = nodeType;
051: }
052:
053: public static AbstractPattern create(AbstractPattern parent,
054: int nodeType) {
055: if (nodeType == NODE && parent instanceof FromParent
056: && parent._parent instanceof FromContext) {
057: FromContext context = (FromContext) parent._parent;
058:
059: return new FromContext(context.getCount() + 1);
060: } else
061: return new NodeTypePattern(parent, nodeType);
062: }
063:
064: /**
065: * The node-type priority is less than nodes.
066: */
067: public double getPriority() {
068: if (_parent instanceof Axis && _parent.getParent() != null
069: && !(_parent.getParent() instanceof FromRoot)
070: && !(_parent.getParent() instanceof FromAny))
071: return 0.5;
072: else
073: return -0.5;
074: }
075:
076: /**
077: * Returns the name of the matching node or '*' if many nodes match.
078: *
079: * <p>The Xsl package uses this to speed template matching.
080: */
081: public String getNodeName() {
082: switch (_nodeType) {
083: case Node.TEXT_NODE: // cdata, too?
084: return "#text";
085:
086: case Node.DOCUMENT_NODE:
087: return "#document";
088:
089: case Node.COMMENT_NODE:
090: return "#comment";
091:
092: default:
093: return "*";
094: }
095: }
096:
097: /**
098: * Returns the matching node type.
099: */
100: public int getNodeType() {
101: return _nodeType;
102: }
103:
104: /**
105: * Returns true if the pattern is strictly ascending.
106: */
107: public boolean isStrictlyAscending() {
108: if (_parent != null)
109: return _parent.isStrictlyAscending();
110: else
111: return true;
112: }
113:
114: /**
115: * Matches if the node type matches.
116: *
117: * @param node the current node
118: * @param env the variable environment
119: *
120: * @return true if the node matches the node type
121: */
122: public boolean match(Node node, ExprEnvironment env)
123: throws XPathException {
124: if (node == null)
125: return false;
126:
127: if (_nodeType == Node.ATTRIBUTE_NODE) {
128: if (node.getNodeType() != Node.ATTRIBUTE_NODE)
129: return false;
130: else if (XMLNS.equals(node.getNamespaceURI()))
131: return false;
132: } else if (node.getNodeType() == _nodeType) {
133: } else if (_nodeType == ANY) {
134: } else if (_nodeType == NODE && !(node instanceof Document)) {
135: } else
136: return false;
137:
138: return _parent == null || _parent.match(node, env);
139: }
140:
141: /**
142: * Copies the node matching portion of the pattern, i.e. the section
143: * only applying to the current axis.
144: */
145: public AbstractPattern copyPosition() {
146: if (_match == null) {
147: AbstractPattern parent = null;
148: if (_parent != null)
149: parent = _parent.copyPosition();
150: _match = new NodeTypePattern(parent, _nodeType);
151: }
152:
153: return _match;
154: }
155:
156: /**
157: * Returns true if the two patterns are equal.
158: */
159: public boolean equals(Object b) {
160: if (!(b instanceof NodeTypePattern))
161: return false;
162:
163: NodeTypePattern bPattern = (NodeTypePattern) b;
164:
165: return (_nodeType == bPattern._nodeType && (_parent == bPattern._parent || (_parent != null && _parent
166: .equals(bPattern._parent))));
167: }
168:
169: /**
170: * Returns the printable representation of the pattern.
171: */
172: public String toString() {
173: String prefix;
174:
175: if (_parent == null)
176: prefix = "";
177: else if (_parent instanceof FromChildren)
178: prefix = _parent.getPrefix();
179: else
180: prefix = _parent.toString();
181:
182: switch (_nodeType) {
183: case ANY:
184: if (!(_parent instanceof FromSelf))
185: return prefix + "node()";
186: else if (_parent._parent == null)
187: return ".";
188: else
189: return _parent.getPrefix() + ".";
190:
191: case NODE:
192: return prefix + "node()";
193:
194: case Node.PROCESSING_INSTRUCTION_NODE:
195: return prefix + "pi()";
196: case Node.ATTRIBUTE_NODE:
197: return prefix + "*";
198: case Node.ELEMENT_NODE:
199: return prefix + "*";
200: case Node.COMMENT_NODE:
201: return prefix + "comment()";
202: case Node.TEXT_NODE:
203: return prefix + "text()";
204: case Node.ENTITY_REFERENCE_NODE:
205: return prefix + "er()";
206: default:
207: return super.toString();
208: }
209: }
210: }
|