Shahid4

xml.d edit 2

May 1st, 2012
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 14.85 KB | None | 0 0
  1. --- a/xml.d 2012-04-30 22:58:38.496710573 +0100
  2. +++ b/xml.d 2012-05-01 13:25:09.486874758 +0100
  3. @@ -842,14 +842,14 @@
  4.         debug(xpath)logline("Got xpath "~to!string(xpath)~" in node "~to!string(getName)~"\n");
  5.         R truncxpath;
  6.         auto nextnode = getNextNode(xpath,truncxpath);
  7. -       R attrmatch;
  8. +       R predmatch;
  9.         // XXX need to be able to split the attribute match off even when it doesn't have [] around it
  10.         ptrdiff_t offset = nextnode.length - find(nextnode, cast(R)"[").length;
  11.         if (offset != nextnode.length) {
  12.             // rip out attribute string
  13. -           attrmatch = nextnode[offset..nextnode.length];
  14. +           predmatch = nextnode[offset..nextnode.length];
  15.             nextnode = nextnode[0..offset];
  16. -           debug(xpath)logline("Found attribute chunk: "~to!string(attrmatch)~"\n");
  17. +           debug(xpath)logline("Found predicate chunk: "~to!string(predmatch)~"\n");
  18.         }
  19.         debug(xpath)logline("Looking for "~to!string(nextnode)~"\n");
  20.         XmlNode[]retarr;
  21. @@ -858,7 +858,13 @@
  22.             // we were searching for nodes, and this is one
  23.             debug(xpath)logline("Found a node we want! name is: "~to!string(getName)~"\n");
  24.             retarr ~= this;
  25. -       } else foreach(child;getChildren) if (!child.isCData && !child.isXmlComment && !child.isXmlPI && child.matchXPathPredicate(attrmatch,caseSensitive)) {
  26. +       } else if (nextnode.front == '@') {
  27. +           if( matchXPathPredicate(nextnode, caseSensitive)) {
  28. +               auto attr = getWSToken(nextnode);
  29. +               attr.popFront();
  30. +               retarr ~= new CData!R(getAttribute(attr));
  31. +           }
  32. +       } else foreach(child;getChildren) if (!child.isCData && !child.isXmlComment && !child.isXmlPI && child.matchXPathPredicate(predmatch,caseSensitive)) {
  33.             if (!nextnode.length || (caseSensitive && child.getName == nextnode) || (!caseSensitive && !icmp(child.getName(), nextnode))) {
  34.                 // child that matches the search string, pass on the truncated string
  35.                 debug(xpath)logline("Sending "~to!string(truncxpath)~" to "~to!string(child.getName)~"\n");
  36. @@ -875,152 +881,139 @@
  37.         return retarr;
  38.     }
  39.  
  40. -   private bool matchXPathPredicate(R attrstr,bool caseSen) {
  41. -       debug(xpath)logline("matching attribute string "~to!string(attrstr)~"\n");
  42. +   private bool matchXPathPredicate(R predstr,bool caseSen) {
  43. +       debug(xpath)logline("matching predicate string "~to!string(predstr)~"\n");
  44.         // strip off the encasing [] if it exists
  45. -       if (!attrstr.length) {
  46. +       if (!predstr.length) {
  47.             return true;
  48.         }
  49. -       if (attrstr.front == '[' && attrstr.back == ']') {
  50. -           attrstr.popFront();
  51. -           attrstr.popBack();
  52. -       } else if (attrstr.front == '[' || attrstr.back == ']') {
  53. +       if (predstr.front == '[' && predstr.back == ']') {
  54. +           predstr.popFront();
  55. +           predstr.popBack();
  56. +       } else if (predstr.front == '[' || predstr.back == ']') {
  57.             // this seems to be malformed
  58. -           throw new XPathError("got malformed attribute match "~to!string(attrstr)~"\n");
  59. +           throw new XPathError("got malformed predicate match "~to!string(predstr)~"\n");
  60.         }
  61.         // rip apart the xpath predicate assuming it's node and attribute matches
  62. -       R[]attrlist;
  63. +       R[]predlist;
  64.         // basically, we're splitting on " and " and " or ", but while respecting []
  65.         int bcount = 0, i = 0;
  66.         ptrdiff_t lslice = 0;
  67. -       R tmpattrstr = attrstr;
  68. -       //foreach (i,c;attrstr) {
  69. -       while(!tmpattrstr.empty()) {
  70. -           auto c = tmpattrstr.front;
  71. -           if (c == '[') {
  72. +       //foreach (i,c;predstr) {
  73. +       R tmpstr = predstr.save;
  74. +       for( dchar quote = '\0'; !tmpstr.empty(); ) {
  75. +           auto c = tmpstr.front;
  76. +           if( quote != '\0' ) {
  77. +               if( quote == c ) {
  78. +                   quote = '\0';
  79. +               }
  80. +           } else if (c == '\'' || c == '"' ) {
  81. +               quote = c;
  82. +           } else if (c == '[') {
  83.                 bcount++;
  84.             } else if (c == ']') {
  85.                 bcount--;
  86.             } else if (bcount == 0 && c == ' ') {
  87.                 if (i != lslice) {
  88. -                   attrlist ~= attrstr[lslice..i];
  89. +                   predlist ~= predstr[lslice..i];
  90.                 }
  91.                 lslice = i+1;
  92.             }
  93.             i++;
  94. -           tmpattrstr.popFront();
  95. +           tmpstr.popFront();
  96.         }
  97.         // tack the last one on
  98. -       attrlist ~= attrstr[lslice..attrstr.length];
  99. +       predlist ~= predstr[lslice..predstr.length];
  100.         // length must be odd, otherwise the string is jank
  101. -       if (!(attrlist.length%2)) throw new XPathError("Encountered a janky predicate: "~to!string(attrstr));
  102. +       if (!(predlist.length%2)) throw new XPathError("Encountered a janky predicate: "~to!string(predstr));
  103.         // verify that odd numbers are "and" or "or"
  104. -       foreach (j,attr;attrlist) if (j%2 && attr != cast(R)"and" && attr != cast(R)"or") {
  105. +       foreach (j,attr;predlist) if (j%2 && attr != cast(R)"and" && attr != cast(R)"or") {
  106.             throw new XPathError("Encountered consecutive terms not separated by \"and\" or \"or\" starting at: "~to!string(attr));
  107.         } else if (!(j%2) && (attr == cast(R)"and" || attr == cast(R)"or")) {
  108. -           throw new XPathError("Encountered consecutive joining terms (\"and\" or \"or\") in: "~to!string(attrstr));
  109. +           throw new XPathError("Encountered consecutive joining terms (\"and\" or \"or\") in: "~to!string(predstr));
  110.         }
  111.         bool[]res;
  112. -       res.length = attrlist.length;
  113. +       res.length = predlist.length;
  114.         int numOrdTerms = 0;
  115. -       debug(xpath)foreach (attr;attrlist) {
  116. -           logline("Term: "~to!string(attr)~"\n");
  117. +       debug(xpath)foreach (pred;predlist) {
  118. +           logline("Term: "~to!string(pred)~"\n");
  119.         }
  120. -       foreach (j,attr;attrlist) if (!(j%2)) {
  121. -           debug(xpath)logline("matching on "~to!string(attr)~"\n");
  122. +       foreach (j,pred;predlist) if (!(j%2)) {
  123. +           debug(xpath)logline("matching on "~to!string(pred)~"\n");
  124. +           bool isattr   = false;      // is elem1 @attribute
  125. +           bool verbatim = false;      // is elem2 quoted string
  126. +           R elem1;            // Left of comparator
  127. +           R comparator;           // null, ">","<","=", ">=","<=","!="
  128. +           R elem2;            // right of comparator
  129. +
  130. +           if (pred.front == '@') {
  131. +               isattr = true;
  132. +               pred.popFront();
  133. +           }
  134. +           // TODO XXX check elem1/elem2 is an XPath func()
  135. +           elem1 = getWSToken(pred);
  136. +           pred = stripLeft(pred);
  137. +           // if there is still data in pred, it's time to look for a comparison operator
  138. +           if (pred.length) {
  139. +               // figure out what comparison needs to be done
  140. +               auto secelem = pred.save;
  141. +               if (!secelem.empty()) secelem.popFront();
  142. +               if (!secelem.empty() && (pred.front == '<' || pred.front == '>' || pred.front == '!') && secelem.front == '=') {
  143. +                   comparator = pred[0..2];
  144. +                   popN(pred, 2);
  145. +                   pred = stripLeft(pred);
  146. +               } else if (pred.front == '<' || pred.front == '>' || pred.front == '=') {
  147. +                   comparator = pred[0..1];
  148. +                   pred.popFront();
  149. +                   pred = stripLeft(pred);
  150. +               } else {
  151. +                   throw new XPathError("Could not determine comparator at: "~to!string(pred));
  152. +               }
  153. +               secelem = pred.save;
  154. +               if (!secelem.empty()) secelem.popFront();
  155. +               if (secelem.empty() && !isNumeric(to!string([pred.front]))) {
  156. +                   throw new XPathError("Badly formed XPath query: Non-numeric comparands must be quoted ("~to!string(pred)~")");
  157. +               }
  158. +               // strip off quotes if necessary
  159. +               if (pred.back == '"' && pred.front == '"') {
  160. +                   pred.popFront();
  161. +                   pred.popBack();
  162. +                   verbatim = true;
  163. +               } else if (pred.back == '"' || pred.front == '"') {
  164. +                   throw new XPathError("Badly formed XPath query: Missing quote ("~to!string(pred)~")");
  165. +               }
  166. +           }
  167. +           elem2 = pred.save;
  168.             // check to see if we're doing an attribute match
  169.             // there should be NO zero-length strings this far in
  170. -           if (attr.front == '@') {
  171. -               attr.popFront();
  172. -               R comparator;
  173. -               auto attrname = getWSToken(attr);
  174. -               bool verbatim = false;
  175. -               attr = stripLeft(attr);
  176. -               // if there is still data in attr, it's time to look for a comparison operator
  177. -               if (attr.length) {
  178. -                   // figure out what comparison needs to be done
  179. -                   auto secelem = attr.save;
  180. -                   if (!secelem.empty()) secelem.popFront();
  181. -                   if (!secelem.empty() && (attr.front == '<' || attr.front == '>' || attr.front == '!') && secelem.front == '=') {
  182. -                       comparator = attr[0..2];
  183. -                       popN(attr, 2);
  184. -                       attr = stripLeft(attr);
  185. -                   } else if (attr.front == '<' || attr.front == '>' || attr.front == '=') {
  186. -                       comparator = attr[0..1];
  187. -                       attr.popFront();
  188. -                       attr = stripLeft(attr);
  189. -                   } else {
  190. -                       throw new XPathError("Could not determine comparator at: "~to!string(attr));
  191. -                   }
  192. -                   secelem = attr.save;
  193. -                   if (!secelem.empty()) secelem.popFront();
  194. -                   if (secelem.empty() && !isNumeric(to!string([attr.front]))) {
  195. -                       throw new XPathError("Badly formed XPath query: Non-numeric comparands must be quoted ("~to!string(attr)~")");
  196. -                   }
  197. -                   // strip off quotes if necessary
  198. -                   if (attr.back == '"' && attr.front == '"') {
  199. -                       attr.popFront();
  200. -                       attr.popBack();
  201. -                       verbatim = true;
  202. -                   } else if (attr.back == '"' || attr.front == '"') {
  203. -                       throw new XPathError("Badly formed XPath query: Missing quote ("~to!string(attr)~")");
  204. -                   }
  205. -               }
  206. -               // make sure that if we pulled a comparator, there's something to compare on the other side
  207. -               if (comparator.length && !attr.length) throw new XPathError("Got a comparator without anything to compare");
  208. -               if (!hasAttribute(attrname)) {
  209. -                   debug(xpath)logline("could not find "~to!string(attrname)~"\n");
  210. +           if ( isattr ) {
  211. +               if (!hasAttribute(elem1)) {
  212. +                   debug(xpath)logline("could not find attr "~to!string(elem1)~"\n");
  213.                     res[j] = false;
  214.                     continue;
  215.                 }
  216. -               if (comparator.length) {
  217. -                   bool lres,neg = false,i1num = isNumeric(to!string(getAttribute(attrname))),i2num = isNumeric(to!string(attr));
  218. -                   double i1,i2;
  219. -                   // currently ignoring verbatim in this section of code
  220. -                   // we can't compare non-numerics without quotes
  221. -                   if (!verbatim && (!i1num || !i2num)) {
  222. -                       //res[j] = false;
  223. -                       //continue;
  224. -                       throw new XPathError("Badly formed XPath query: Non-numeric comparands must be quoted ("~to!string(attr)~")");
  225. -                   }
  226. -                   // get numeric equivalents
  227. -                   if (i1num) i1 = to!double(to!string(getAttribute(attrname)));
  228. -                   if (i2num) i2 = to!double(to!string(attr));
  229. -                   if (comparator.front == '<') {
  230. -                       if (i1num && i2num) {
  231. -                           lres = (i1 < i2);
  232. -                       } else {
  233. -                           lres = (getAttribute(attrname) < attr);
  234. -                       }
  235. -                   } else if (comparator.front == '>') {
  236. -                       if (i1num && i2num) {
  237. -                           lres = (i1 > i2);
  238. -                       } else {
  239. -                           lres = (getAttribute(attrname) > attr);
  240. -                       }
  241. -                   } else if (comparator.front == '!') neg = true;
  242. -                   // check to see if equality is also called for
  243. -                   if (comparator.back == '=') {
  244. -                       if (verbatim) {
  245. -                           if ((getAttribute(attrname) != attr && caseSen) || (icmp(getAttribute(attrname), attr) != 0 && !caseSen)) {
  246. -                               debug(xpath)logline("search value "~to!string(attr)~" did not match attribute value "~to!string(getAttribute(attrname))~"\n");
  247. -                               lres = false;
  248. -                           } else {
  249. -                               lres = true;
  250. -                           }
  251. -                       } else {
  252. -                           lres |= (i1 == i2);
  253. -                       }
  254. -                       if (neg) lres = !lres;
  255. -                   }
  256. -                   res[j] = lres;
  257. +               if( comparator.length == 0 ) {
  258. +                   // Just check for existance
  259. +                   res[j] = true;
  260.                     continue;
  261.                 }
  262. -               res[j] = true;
  263. -               continue;
  264. +               res[j] = compareXPathPredicate( elem1, comparator, elem2, getAttribute(elem1), caseSen );
  265.             }
  266. +           else if (true) {
  267. +               // assume elem1 is a tag
  268. +               //if (!comparator.length || !elem2.length) throw new XPathError("Is this really an Error?");
  269. +               foreach(child;getChildren) {
  270. +                   if( child.getName != elem1 || child.isCData || child.isXmlComment || child.isXmlPI )
  271. +                       continue;
  272. +              
  273. +                   if( compareXPathPredicate( elem1, comparator, elem2, child.getCData, caseSen )) {
  274. +                       res[j] = true;
  275. +                       break;
  276. +                   }
  277. +               }
  278. +           }              
  279.             // XXX take care of other types of matches other than attribute matches
  280. -       } else if (attr == cast(R)"or") {
  281. +       } else if (pred == cast(R)"or") {
  282.             numOrdTerms++;
  283.         }
  284.         // collect "and" terms into "or" groups
  285. @@ -1029,9 +1022,9 @@
  286.         ordTerms[0] = res[0];
  287.         debug(xpath)logline("res[0]="~to!(string)(res[0])~"\n");
  288.         numOrdTerms = 0; // we're using this as current position, now
  289. -       foreach (j,attr;attrlist) if (j%2) {
  290. +       foreach (j,attr;predlist) if (j%2) {
  291.             if (attr == cast(R)"and") {
  292. -               debug(xpath)logline("combining anded terms on ord term "~to!(string)(numOrdTerms)~" and i="~to!(string)(j)~" with res.length="~to!(string)(res.length)~" and attrlist.length="~to!(string)(attrlist.length)~"\n");
  293. +               debug(xpath)logline("combining anded terms on ord term "~to!(string)(numOrdTerms)~" and i="~to!(string)(j)~" with res.length="~to!(string)(res.length)~" and predlist.length="~to!(string)(predlist.length)~"\n");
  294.                 ordTerms[numOrdTerms] &= res[j+1];
  295.                 debug(xpath)logline("res["~to!(string)(j+1)~"]="~to!(string)(res[j+1])~"\n");
  296.             } else if (attr == cast(R)"or") {
  297. @@ -1047,7 +1040,59 @@
  298.         debug(xpath)logline("Ended up with "~to!(string)(ret)~"\n");
  299.         return ret;
  300.     }
  301. -  
  302. +
  303. +   private bool compareXPathPredicate( R elem1, R comparator, R elem2, R elem1value, bool caseSen )
  304. +   {
  305. +       // make sure that if we pulled a comparator, there's something to compare on the other side
  306. +       if (comparator.length && !elem2.length) throw new XPathError("Got a comparator without anything to compare");
  307. +       if (comparator.length) {
  308. +           bool lres,i1num = isNumeric(to!string(elem1value)),i2num = isNumeric(to!string(elem2));
  309. +           if (comparator.front == '<' || comparator.front == '>') {
  310. +               // Must be numeric
  311. +               if( !i2num )
  312. +                   throw new XPathError("Badly formed XPath query: comparator '"~to!string(comparator)~"' requires a numeric operand Not ("~to!string(elem2)~")");
  313. +               if( !i1num ) {
  314. +                   return false;
  315. +               }
  316. +          
  317. +               // get numeric equivalents
  318. +               double i1 = to!double(to!string(elem1value));
  319. +               double i2 = to!double(to!string(elem2));
  320. +
  321. +               if (comparator.front == '<') {
  322. +                   lres = i1 < i2;
  323. +               } else /*if (comparator.front == '>')*/ {
  324. +                   lres = i1 > i2;
  325. +               }
  326. +               // check to see if equality is also called for
  327. +               if (comparator.back == '=') {
  328. +                   lres |= (i1 == i2);
  329. +               }
  330. +           } else {
  331. +               bool neg = false;
  332. +               if (comparator.front == '!') neg = true;
  333. +
  334. +               if( !i1num || !i2num ) {
  335. +                   if ((elem1value != elem2 && caseSen) || (icmp(elem1value, elem2) != 0 && !caseSen)) {
  336. +                       debug(xpath)logline("search value "~to!string(elem2)~" did not match attribute value "~to!string(elem1value)~"\n");
  337. +                       lres = false;
  338. +                   } else {
  339. +                       lres = true;
  340. +                   }
  341. +               } else {
  342. +                   // get numeric equivalents
  343. +                   double i1 = to!double(to!string(elem1value));
  344. +                   double i2 = to!double(to!string(elem2));
  345. +                   lres = (i1 == i2);
  346. +               }
  347. +               if (neg) lres = !lres;
  348. +           }
  349. +           return lres;
  350. +       }
  351. +       return false;
  352. +   }
  353. +
  354. +
  355.     private bool isDeepPath(R xpath) {
  356.         // check to see if we're currently searching a deep path
  357.         auto secelem = xpath.save;
  358. @@ -1440,6 +1485,7 @@
  359.    *--------------------------
  360.    */
  361.  public int prealloc = 50;
  362. +///ditto
  363.  class XmlDocument(R=string) : XmlNode!R {
  364.     // this should inherit the reset and toXml that we want
  365.     protected XmlNode!R[]xmlNodes;
Advertisement
Add Comment
Please, Sign In to add comment