1 package org.softnetwork.xml.dom.xpath;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.List;
6 import java.util.StringTokenizer;
7 import org.w3c.dom.Document;
8 import org.w3c.dom.Element;
9 import org.w3c.dom.Node;
10
11 /**
12 * @author stephane.manciot@ebiznext.com
13 *
14 */
15 public final class LookupService implements XPath {
16
17 final static String XPATH_TOKENIZER = XPATH_COND_BEGIN + ","
18 + XPATH_COND_END + ","
19 + XPATH_SEPARATOR;
20
21 private LookupService() {
22 }
23
24 public static Node[] selectNodes(Node current, String xPath)
25 throws XPathFormatException {
26
27 if (xPath == null)
28 return EMPTY;
29 if (current == null)
30 return EMPTY;
31 boolean fromDocument = xPath.startsWith(XPATH_SEPARATOR);
32 StringTokenizer tokens = new StringTokenizer(xPath, XPATH_TOKENIZER,
33 true);
34 if (fromDocument) {
35 if (current.getOwnerDocument() != null)
36 current = current.getOwnerDocument();
37 if (current instanceof Document)
38 current = ((Document) current).getDocumentElement();
39 String tagName = current.getNodeName();
40 String token = null;
41 while ((tokens.hasMoreElements())) {
42 token = tokens.nextToken();
43 if (!token.equals(XPATH_SEPARATOR))
44 break;
45 }
46 if (!tagName.equals(token))
47 return EMPTY;
48 }
49 List in = new ArrayList();
50 in.add(current);
51 return selectNodes(new ArrayList(), in, select(tokens));
52 }
53
54 private static final XPathNode[] select(StringTokenizer tokens)
55 throws XPathFormatException {
56 List nodes = new ArrayList();
57 while (tokens.hasMoreTokens()) {
58 String token = tokens.nextToken();
59 if (!token.equals(XPATH_SEPARATOR)
60 && !token.equals(XPATH_COND_BEGIN)) {
61 String name = token;
62 List filters = new ArrayList();
63 if (tokens.hasMoreElements()) {
64 token = tokens.nextToken();
65 if (token.equals(XPATH_COND_BEGIN)) {
66 do {
67 XPathFilter filter = null;
68 String filterTokens = "";
69 while ((tokens.hasMoreElements())
70 && !(token = tokens.nextToken())
71 .equals(XPATH_COND_END))
72 filterTokens += token;
73 filter = new XPathFilter(filterTokens);
74 filters.add(filter);
75 } while ((tokens.hasMoreElements())
76 && (token = tokens.nextToken())
77 .equals(XPATH_COND_BEGIN));
78 }
79 }
80 nodes.add(new XPathNode(name, (XPathFilter[]) filters
81 .toArray(new XPathFilter[0])));
82 }
83 }
84 return (XPathNode[]) nodes.toArray(new XPathNode[0]);
85 }
86
87 private static final Node[] selectNodes(List matches, List in,
88 XPathNode[] nodes) throws XPathFormatException {
89
90
91 int nb = nodes.length;
92 if (nb == 0)
93 return (Node[]) in.toArray(new Node[0]);
94 Node current = null;
95 Node[] from = (Node[]) in.toArray(new Node[0]);
96 int len = from.length;
97 in.clear();
98 int i = 0;
99 for (; i < len; i++) {
100 current = from[i];
101 XPathNode node = nodes[0];
102 in.addAll(Arrays.asList(node.selectNodes(current)));
103 if (nb > 1) {
104 XPathNode[] copy = new XPathNode[nb - 1];
105 System.arraycopy(nodes, 1, copy, 0, nb - 1);
106 selectNodes(matches, in, copy);
107 } else
108 matches.addAll(in);
109 }
110 return (Node[]) matches.toArray(new Node[0]);
111 }
112
113 public static Element[] selectElements(Element current, String xPath)
114 throws XPathFormatException {
115
116
117 if (xPath == null)
118 return EMPTY;
119 if (current == null)
120 return EMPTY;
121
122 boolean fromDocument = xPath.startsWith(XPATH_SEPARATOR);
123 if (fromDocument
124 && !xPath.startsWith(XPATH_SEPARATOR + current.getTagName())) {
125 String currentXPath = XPathTools.getXpath(current);
126 if (!xPath.startsWith(currentXPath))
127 xPath = currentXPath + xPath;
128 }
129
130 StringTokenizer tokens = new StringTokenizer(xPath, XPATH_TOKENIZER,
131 true);
132 if (fromDocument) {
133 current = current.getOwnerDocument().getDocumentElement();
134 String tagName = current.getTagName();
135 String token = null;
136 while ((tokens.hasMoreElements())) {
137 token = tokens.nextToken();
138 if (!token.equals(XPATH_SEPARATOR))
139 break;
140 }
141 if (!tagName.equals(token))
142 return EMPTY;
143 }
144 List in = new ArrayList();
145 in.add(current);
146 List elements = new ArrayList();
147 while (tokens.hasMoreTokens()) {
148 String token = tokens.nextToken();
149 if (!token.equals(XPATH_SEPARATOR)
150 && !token.equals(XPATH_COND_BEGIN)) {
151 String name = token;
152 List filters = new ArrayList();
153 if (tokens.hasMoreElements()) {
154 token = tokens.nextToken();
155 if (token.equals(XPATH_COND_BEGIN)) {
156 do {
157 XPathFilter filter = null;
158 String filterTokens = "";
159 while ((tokens.hasMoreElements())
160 && !(token = tokens.nextToken())
161 .equals(XPATH_COND_END))
162 filterTokens += token;
163 filter = new XPathFilter(filterTokens);
164 filters.add(filter);
165 } while ((tokens.hasMoreElements())
166 && (token = tokens.nextToken())
167 .equals(XPATH_COND_BEGIN));
168 }
169 }
170 elements.add(new XPathElement(name, (XPathFilter[]) filters
171 .toArray(new XPathFilter[0])));
172 }
173 }
174 Element[] selected = selectElements(new ArrayList(), in,
175 (XPathElement[]) elements.toArray(new XPathElement[0]));
176
177
178
179
180
181
182 return selected;
183 }
184
185 private static final Element[] selectElements(List matches, List in,
186 XPathElement[] elements) throws XPathFormatException {
187
188
189 int nb = elements.length;
190 if (nb == 0)
191 return (Element[]) in.toArray(new Element[0]);
192 Element current = null;
193 Element[] from = (Element[]) in.toArray(new Element[0]);
194 int len = from.length;
195 in.clear();
196 int i = 0;
197 for (; i < len; i++) {
198 current = from[i];
199 XPathElement element = elements[0];
200 in.addAll(Arrays.asList(element.selectElements(current)));
201 if (nb > 1) {
202 XPathElement[] copy = new XPathElement[nb - 1];
203 System.arraycopy(elements, 1, copy, 0, nb - 1);
204 selectElements(matches, in, copy);
205 } else
206 matches.addAll(in);
207 }
208 return (Element[]) matches.toArray(new Element[0]);
209 }
210
211 }