Shahid4

xml.d edit 1

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