1 21 22 23 24 package nu.xom.xinclude; 25 26 import java.util.ArrayList ; 27 import java.util.List ; 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 50 class XPointer { 51 52 53 private XPointer() {} 55 56 57 public static Nodes query(Document doc, String xptr) 58 throws XPointerSyntaxException, XPointerResourceException { 59 60 Nodes result = new Nodes(); 61 boolean found = false; 62 63 try { 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 List elementSchemeData = findElementSchemeData(xptr); 75 if (elementSchemeData.size() == 0) { 76 throw new XPointerSyntaxException( 79 "No supported XPointer schemes found" 80 ); 81 } 82 83 for (int i = 0; i < elementSchemeData.size(); i++) { 84 String currentData = (String ) (elementSchemeData.get(i)); 85 int[] keys = new int[0]; 86 ParentNode current = doc; 87 if (currentData.indexOf('/') == -1) { 88 try { 90 new Element(currentData); 91 } 92 catch (IllegalNameException inex) { 93 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 id = currentData.substring( 112 0, currentData.indexOf('/')); 113 try { 116 new Element(id); 117 } 118 catch (XMLException inex) { 119 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 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 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 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 part = new StringBuffer (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 (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 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 findElementSchemeData(String xpointer) 215 throws XPointerSyntaxException { 216 217 List result = new ArrayList (1); 218 219 StringBuffer xptr = new StringBuffer (xpointer.trim()); 220 StringBuffer scheme = new StringBuffer (); 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 try { 231 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; i++; 240 StringBuffer schemeData = new StringBuffer (); 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 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 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 |