1 package org.unicode.cldr.util; 2 3 /** This class implements the parsing for XPaths */ 4 public abstract class XPathParser implements XPathValue { 5 /** 6 * Parse a string component. Will call handleXX() functions when parsed. 7 * 8 * @param xPath the path string 9 * @param initial boolean, if true, will call clearElements() before adding, and make 10 * requiredPrefix // instead of / 11 */ handleParse(String xPath, boolean initial)12 protected void handleParse(String xPath, boolean initial) { 13 String lastAttributeName = ""; 14 String requiredPrefix = "/"; 15 if (initial) { 16 handleClearElements(); 17 requiredPrefix = "//"; 18 } 19 if (!xPath.startsWith(requiredPrefix)) { 20 parseError(xPath, 0); 21 } 22 int stringStart = requiredPrefix.length(); // skip prefix 23 char state = 'p'; 24 // since only ascii chars are relevant, use char 25 int len = xPath.length(); 26 for (int i = 2; i < len; ++i) { 27 char cp = xPath.charAt(i); 28 if (cp != state && (state == '\"' || state == '\'')) { 29 continue; // stay in quotation 30 } 31 switch (cp) { 32 case '/': 33 if (state != 'p' || stringStart >= i) { 34 parseError(xPath, i); 35 } 36 if (stringStart > 0) { 37 handleAddElement(xPath.substring(stringStart, i)); 38 } 39 stringStart = i + 1; 40 break; 41 case '[': 42 if (state != 'p' || stringStart >= i) { 43 parseError(xPath, i); 44 } 45 if (stringStart > 0) { 46 handleAddElement(xPath.substring(stringStart, i)); 47 } 48 state = cp; 49 break; 50 case '@': 51 if (state != '[') { 52 parseError(xPath, i); 53 } 54 stringStart = i + 1; 55 state = cp; 56 break; 57 case '=': 58 if (state != '@' || stringStart >= i) { 59 parseError(xPath, i); 60 } 61 lastAttributeName = xPath.substring(stringStart, i); 62 state = cp; 63 break; 64 case '\"': 65 case '\'': 66 if (state == cp) { // finished 67 if (stringStart > i) { 68 parseError(xPath, i); 69 } 70 handleAddAttribute(lastAttributeName, xPath.substring(stringStart, i)); 71 state = 'e'; 72 break; 73 } 74 if (state != '=') { 75 parseError(xPath, i); 76 } 77 stringStart = i + 1; 78 state = cp; 79 break; 80 case ']': 81 if (state != 'e') { 82 parseError(xPath, i); 83 } 84 state = 'p'; 85 stringStart = -1; 86 break; 87 } 88 } 89 // check to make sure terminated 90 if (state != 'p' || stringStart >= xPath.length()) { 91 parseError(xPath, xPath.length()); 92 } 93 if (stringStart > 0) { 94 handleAddElement(xPath.substring(stringStart, xPath.length())); 95 } 96 } 97 98 /** 99 * Standardized code for throwing a parse error 100 * 101 * @param s 102 * @param i 103 */ parseError(String s, int i)104 protected void parseError(String s, int i) { 105 throw new IllegalArgumentException("Malformed xPath '" + s + "' at " + i); 106 } 107 108 /** Subclass implementation */ handleClearElements()109 protected abstract void handleClearElements(); 110 111 /** 112 * Subclass implementation 113 * 114 * @param element 115 */ handleAddElement(String element)116 protected abstract void handleAddElement(String element); 117 118 /** Subclass implementation */ handleAddAttribute(String attribute, String value)119 protected abstract void handleAddAttribute(String attribute, String value); 120 } 121