KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nu > xom > xinclude > XPointer


1 /* Copyright 2002-2004 Elliotte Rusty Harold
2    
3    This library is free software; you can redistribute it and/or modify
4    it under the terms of version 2.1 of the GNU Lesser General Public
5    License as published by the Free Software Foundation.
6    
7    This library is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10    GNU Lesser General Public License for more details.
11    
12    You should have received a copy of the GNU Lesser General Public
13    License along with this library; if not, write to the
14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15    Boston, MA 02111-1307 USA
16    
17    You can contact Elliotte Rusty Harold by sending e-mail to
18    elharo@metalab.unc.edu. Please include the word "XOM" in the
19    subject line. The XOM home page is located at http://www.xom.nu/
20 */

21
22
23
24 package nu.xom.xinclude;
25
26 import java.util.ArrayList JavaDoc;
27 import java.util.List JavaDoc;
28
29 import nu.xom.Attribute;
30 import nu.xom.Document;
31 import nu.xom.Element;
32 import nu.xom.IllegalNameException;
33 import nu.xom.Node;
34 import nu.xom.Nodes;
35 import nu.xom.ParentNode;
36 import nu.xom.XMLException;
37
38 /**
39  *
40  * <p>
41  * Right now this is just for XInclude, and hence is non-public.
42  * Once it's more baked it will probably become public and move
43  * to a package of its own.
44  * </p>
45  *
46  * @author Elliotte Rusty Harold
47  * @version 1.0
48  *
49  */

50 class XPointer {
51     
52     
53     // prevent instantiation
54
private XPointer() {}
55     
56     
57     public static Nodes query(Document doc, String JavaDoc xptr)
58       throws XPointerSyntaxException, XPointerResourceException {
59             
60         Nodes result = new Nodes();
61         boolean found = false;
62         
63         try { // Is this a shorthand XPointer?
64
// Need to include a URI in case this is a colonized scheme name
65
new Element(xptr, "http://www.example.com");
66             Element identified = findByID(doc.getRootElement(), xptr);
67             if (identified != null) {
68                 result.append(identified);
69                 return result;
70             }
71         }
72         catch (IllegalNameException ex) {
73             // not a bare name; try element() scheme
74
List JavaDoc elementSchemeData = findElementSchemeData(xptr);
75             if (elementSchemeData.size() == 0) {
76                 // This may be a legal XPointer, but it doesn't
77
// have an element() scheme so we can't handle it.
78
throw new XPointerSyntaxException(
79                   "No supported XPointer schemes found"
80                 );
81             }
82         
83             for (int i = 0; i < elementSchemeData.size(); i++) {
84                 String JavaDoc currentData = (String JavaDoc) (elementSchemeData.get(i));
85                 int[] keys = new int[0];
86                 ParentNode current = doc;
87                 if (currentData.indexOf('/') == -1) {
88                     // raw id in element like element(f2)
89
try {
90                         new Element(currentData);
91                     }
92                     catch (IllegalNameException inex) {
93                         // not a bare name; and doesn't contain a /
94
// This doesn't adhere to the element scheme.
95
// Therefore, according to the XPointer element
96
// scheme spec, " if scheme data in a pointer
97
// part with the element() scheme does not
98
// conform to the syntax defined in this
99
// section the pointer part does not identify
100
// a subresource."
101
continue;
102                     }
103                     Element identified = findByID(
104                       doc.getRootElement(), currentData);
105                     if (identified != null) {
106                         if (!found) result.append(identified);
107                         found = true;
108                     }
109                 }
110                 else if (!currentData.startsWith("/")) {
111                     String JavaDoc id = currentData.substring(
112                       0, currentData.indexOf('/'));
113                     // Check to make sure this is a legal
114
// XML name/ID value
115
try {
116                         new Element(id);
117                     }
118                     catch (XMLException inex) {
119                         // doesn't adhere to the element scheme spec;
120
// Therefore this pointer part does not identify
121
// a subresource (See 2nd paragraph of section
122
// 3 of http://www.w3.org/TR/xptr-element/ )
123
// This is not a resource error unless no
124
// XPointer part identifies a subresource.
125
continue;
126                     }
127                     current = findByID(doc.getRootElement(), id);
128                     keys = split(currentData.substring(
129                       currentData.indexOf('/')));
130                     
131                     if (current == null) continue;
132                 }
133                 else {
134                     keys = split(currentData);
135                 }
136                 
137                 for (int j = 0; j < keys.length; j++) {
138                     current = findNthChildElement(current, keys[j]);
139                     if (current == null) break;
140                 }
141             
142                 if (current != doc && current != null) {
143                     if (!found) result.append(current);
144                     found = true;
145                 }
146               
147             }
148             
149         }
150         
151         if (found) return result;
152         else {
153             // If we get here and still haven't been able to match an
154
// element, the XPointer has failed.
155
throw new XPointerResourceException(
156               "XPointer " + xptr
157               + " did not locate any nodes in the document "
158               + doc.getBaseURI()
159             );
160         }
161         
162     }
163     
164     
165     private static Element findNthChildElement(
166       ParentNode parent, int position) {
167         // watch out for 1-based indexing of tumblers
168
int elementCount = 1;
169         for (int i = 0; i < parent.getChildCount(); i++) {
170             Node child = parent.getChild(i);
171             if (child instanceof Element) {
172                 if (elementCount == position) return (Element) child;
173                 elementCount++;
174             }
175         }
176         return null;
177     }
178     
179     
180     private static int[] split(String JavaDoc tumbler)
181       throws XPointerSyntaxException {
182   
183         int numberOfParts = 0;
184         for (int i = 0; i < tumbler.length(); i++) {
185           if (tumbler.charAt(i) == '/') numberOfParts++;
186         }
187         
188         int[] result = new int[numberOfParts];
189         int index = 0;
190         StringBuffer JavaDoc part = new StringBuffer JavaDoc(3);
191         try {
192             for (int i = 1; i < tumbler.length(); i++) {
193                 if (tumbler.charAt(i) == '/') {
194                     result[index] = Integer.parseInt(part.toString());
195                     index++;
196                     part = new StringBuffer JavaDoc(3);
197                 }
198                 else {
199                     part.append(tumbler.charAt(i));
200                 }
201             }
202             result[result.length-1] = Integer.parseInt(part.toString());
203         }
204         catch (NumberFormatException JavaDoc ex) {
205             XPointerSyntaxException ex2
206               = new XPointerSyntaxException(tumbler
207                 + " is not syntactically correct", ex);
208             throw ex2;
209         }
210         
211         return result;
212     }
213     
214     private static List JavaDoc findElementSchemeData(String JavaDoc xpointer)
215       throws XPointerSyntaxException {
216         
217         List JavaDoc result = new ArrayList JavaDoc(1);
218         
219         StringBuffer JavaDoc xptr = new StringBuffer JavaDoc(xpointer.trim());
220         StringBuffer JavaDoc scheme = new StringBuffer JavaDoc();
221         int i = 0;
222         while (i < xptr.length()) {
223             char c = xptr.charAt(i);
224             if (c == '(') break;
225             else scheme.append(c);
226             i++;
227         }
228         
229         // need to verify that scheme is a QName
230
try {
231             // ugly hack because Verifier isn't public
232
new Element(scheme.toString(), "http://www.example.com/");
233         }
234         catch (IllegalNameException ex) {
235             throw new XPointerSyntaxException(ex.getMessage());
236         }
237         
238         int open = 1; // parentheses count
239
i++;
240         StringBuffer JavaDoc schemeData = new StringBuffer JavaDoc();
241         try {
242             while (open > 0) {
243                 char c = xptr.charAt(i);
244                 if (c == '^') {
245                     c = xptr.charAt(i+1);
246                     schemeData.append(c);
247                     if (c != '^' && c != '(' && c != ')') {
248                         throw new XPointerSyntaxException(
249                           "Illegal XPointer escape sequence"
250                         );
251                     }
252                     i++;
253                 }
254                 else if (c == '(') {
255                     schemeData.append(c);
256                     open++;
257                 }
258                 else if (c == ')') {
259                     open--;
260                     if (open > 0) schemeData.append(c);
261                 }
262                 else {
263                     schemeData.append(c);
264                 }
265                 i++;
266             }
267         }
268         catch (StringIndexOutOfBoundsException JavaDoc ex) {
269             throw new XPointerSyntaxException("Unbalanced parentheses");
270         }
271         
272         if (scheme.toString().equals("element")) {
273             result.add(schemeData.toString());
274         }
275
276         if (i + 1 < xptr.length()) {
277             result.addAll(findElementSchemeData(xptr.substring(i)));
278         }
279         
280         return result;
281     }
282     
283     
284     public static Element findByID(Element element, String JavaDoc id) {
285          
286         Node current = element;
287         boolean end = false;
288         int index = -1;
289         while (true) {
290             
291             if (current instanceof Element) {
292                 Element currentElement = (Element) current;
293                 for (int i = 0; i < currentElement.getAttributeCount(); i++) {
294                     Attribute att = currentElement.getAttribute(i);
295                     if (att.getType() == Attribute.Type.ID) {
296                         if (att.getValue().trim().equals(id)) {
297                             return currentElement;
298                         }
299                     }
300                 }
301             }
302             
303             if (!end && current.getChildCount() > 0) {
304                current = current.getChild(0);
305                index = 0;
306             }
307             else {
308                 if (end) {
309                     if (current == element) break;
310                 }
311                 end = false;
312                 ParentNode parent = current.getParent();
313                 if (parent.getChildCount() - 1 == index) {
314                     current = parent;
315                     if (current != element) {
316                         parent = current.getParent();
317                         index = parent.indexOf(current);
318                     }
319                     end = true;
320                 }
321                 else {
322                     index++;
323                     current = parent.getChild(index);
324                 }
325             }
326         }
327         
328         return null;
329         
330     }
331
332     
333 }
334
Popular Tags