xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/util/XPathParser.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
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