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.expr;
030:
031: import com.caucho.util.CharBuffer;
032: import com.caucho.xml.QDocumentType;
033: import com.caucho.xml.XmlChar;
034: import com.caucho.xml.XmlUtil;
035: import com.caucho.xpath.Expr;
036: import com.caucho.xpath.ExprEnvironment;
037: import com.caucho.xpath.XPathException;
038: import com.caucho.xpath.pattern.NodeIterator;
039:
040: import org.w3c.dom.Document;
041: import org.w3c.dom.Element;
042: import org.w3c.dom.Node;
043: import org.w3c.dom.NodeList;
044:
045: import java.util.ArrayList;
046: import java.util.Iterator;
047:
048: public class IdExpr extends Expr {
049: private Expr _expr;
050:
051: private ExprEnvironment _lastEnv;
052: private int _lastUseCount;
053: private Node _lastContext;
054: private ArrayList _lastList;
055:
056: public IdExpr(ArrayList<Expr> args) {
057: if (args.size() > 0)
058: _expr = args.get(0);
059: }
060:
061: public boolean isNodeSet() {
062: return true;
063: }
064:
065: /**
066: * Evaluates the expression as a number
067: *
068: * @param node the current node
069: * @param env the variable environment.
070: *
071: * @return the number representation of id
072: */
073: public double evalNumber(Node node, ExprEnvironment env)
074: throws XPathException {
075: String string = evalString(node, env);
076:
077: return stringToNumber(string);
078: }
079:
080: /**
081: * Evaluates the expression as a boolean
082: *
083: * @param node the current node
084: * @param env the variable environment.
085: *
086: * @return true if the node exists
087: */
088: public boolean evalBoolean(Node node, ExprEnvironment env)
089: throws XPathException {
090: return id(node, env).size() > 0;
091: }
092:
093: /**
094: * The string value of the id expression is just the text value of the
095: * first node.
096: *
097: * @param node the current node
098: * @param env the variable environment.
099: *
100: * @return true if the node exists
101: */
102: public String evalString(Node node, ExprEnvironment env)
103: throws XPathException {
104: NodeIterator iter = evalNodeSet(node, env);
105:
106: if (!iter.hasNext())
107: return "";
108:
109: Node qNode = (Node) iter.next();
110: return XmlUtil.textValue(qNode);
111: }
112:
113: /**
114: * The string value of the id expression is just the list of nodes.
115: *
116: * @param node the current node
117: * @param env the variable environment.
118: *
119: * @return true if the node exists
120: */
121: public Object evalObject(Node node, ExprEnvironment env)
122: throws XPathException {
123: ArrayList<Element> list = id(node, env);
124:
125: return list;
126: }
127:
128: /**
129: * Returns the list of string ids.
130: */
131: private ArrayList<Element> id(Node context, ExprEnvironment env)
132: throws XPathException {
133: ArrayList idList = getIdList(context, env);
134: ArrayList<Element> list = new ArrayList<Element>();
135:
136: if (idList == null || idList.size() == 0)
137: return list;
138:
139: Node ptr;
140:
141: if (context instanceof Document)
142: ptr = context;
143: else
144: ptr = context.getOwnerDocument();
145:
146: while ((ptr = XmlUtil.getNext(ptr)) != null) {
147: if (ptr instanceof Element) {
148: Element elt = (Element) ptr;
149:
150: QDocumentType dtd;
151: dtd = (QDocumentType) elt.getOwnerDocument()
152: .getDoctype();
153: String id = null;
154: if (dtd != null)
155: id = (String) dtd.getElementId(elt.getNodeName());
156:
157: if (id != null) {
158: String idValue = elt.getAttribute(id);
159: if (idList.contains(idValue) && !list.contains(elt))
160: list.add(elt);
161: }
162: }
163: }
164:
165: return list;
166: }
167:
168: /**
169: * Evaluates the id expression, returning a list of strings.
170: *
171: * @param env the XPath environment
172: * @param node the context node.
173: *
174: * @return a list of string values.
175: */
176: private ArrayList<String> getIdList(Node node, ExprEnvironment env)
177: throws XPathException {
178: ArrayList<String> idList = new ArrayList<String>();
179:
180: Object obj = _expr.evalObject(node, env);
181: if (obj instanceof NodeList) {
182: NodeList list = (NodeList) obj;
183:
184: int length = list.getLength();
185: for (int i = 0; i < length; i++) {
186: Node value = list.item(i);
187:
188: addText(idList, XmlUtil.textValue(value));
189: }
190: } else if (obj instanceof ArrayList) {
191: ArrayList list = (ArrayList) obj;
192:
193: for (int i = 0; i < list.size(); i++) {
194: Node value = (Node) list.get(i);
195:
196: addText(idList, XmlUtil.textValue(value));
197: }
198: } else if (obj instanceof Iterator) {
199: Iterator iter = (Iterator) obj;
200:
201: while (iter.hasNext()) {
202: Node value = (Node) iter.next();
203:
204: addText(idList, XmlUtil.textValue(value));
205: }
206: } else
207: addText(idList, toString(obj));
208:
209: return idList;
210: }
211:
212: private void addText(ArrayList<String> idList, String text) {
213: int len = text.length();
214: CharBuffer cb = new CharBuffer();
215: int i = 0;
216: int ch = 0;
217: for (; i < len && XmlChar.isWhitespace(text.charAt(i)); i++) {
218: }
219:
220: if (i == len)
221: return;
222:
223: while (i < len) {
224: cb.clear();
225: for (; i < len && !XmlChar.isWhitespace(text.charAt(i)); i++)
226: cb.append(text.charAt(i));
227:
228: idList.add(cb.toString());
229:
230: for (; i < len && XmlChar.isWhitespace(text.charAt(i)); i++) {
231: }
232: }
233: }
234:
235: public String toString() {
236: if (_expr != null)
237: return "id(" + _expr + ")";
238: else
239: return "id()";
240: }
241: }
|