Clover coverage report - Clover results for XOM 1.2d1
Coverage timestamp: Wed Feb 8 2006 08:31:33 EST
file stats: LOC: 586   Methods: 46
NCLOC: 390   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
JaxenNavigator.java 98.9% 97.6% 91.3% 97.1%
coverage coverage
 1    /* Copyright 2005 Elliotte Rusty Harold
 2   
 3    This library is free software; you can redistribute it and/or modify
 4    it under the terms of version 2.1 of the GNU Lesser General Public
 5    License as published by the Free Software Foundation.
 6   
 7    This library is distributed in the hope that it will be useful,
 8    but WITHOUT ANY WARRANTY; without even the implied warranty of
 9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 10    GNU Lesser General Public License for more details.
 11   
 12    You should have received a copy of the GNU Lesser General Public
 13    License along with this library; if not, write to the
 14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 15    Boston, MA 02111-1307 USA
 16   
 17    You can contact Elliotte Rusty Harold by sending e-mail to
 18    elharo@metalab.unc.edu. Please include the word "XOM" in the
 19    subject line. The XOM home page is located at http://www.xom.nu/
 20    */
 21   
 22    package nu.xom;
 23   
 24    /**
 25    * <p>
 26    * Interface between Jaxen and XOM.
 27    * </p>
 28    *
 29    * @author Elliotte Rusty Harold
 30    * @version 1.1.1b1
 31    *
 32    */
 33   
 34    import org.jaxen.DefaultNavigator;
 35    import org.jaxen.FunctionCallException;
 36    import org.jaxen.JaxenConstants;
 37    import org.jaxen.JaxenException;
 38    import org.jaxen.NamedAccessNavigator;
 39    import org.jaxen.UnsupportedAxisException;
 40    import org.jaxen.XPath;
 41    import org.jaxen.util.SingleObjectIterator;
 42   
 43    import java.util.Iterator;
 44    import java.util.List;
 45    import java.util.ArrayList;
 46    import java.util.Map;
 47    import java.util.NoSuchElementException;
 48   
 49   
 50    class JaxenNavigator extends DefaultNavigator implements NamedAccessNavigator {
 51   
 52   
 53    private static final long serialVersionUID = 7008740797833836742L;
 54   
 55   
 56  255 public Iterator getSelfAxisIterator(Object contextNode) {
 57   
 58  255 if (contextNode instanceof Text) {
 59    // wrap text nodes in a list
 60  5 Text node = (Text) contextNode;
 61  5 ArrayList temp = new ArrayList();
 62  5 ParentNode parent = node.getParent();
 63    // parent is never null here due to DocumentFragment
 64  5 int index = parent.indexOf(node);
 65  5 int first = index;
 66  5 int last = index;
 67  5 while (first > 0 && parent.getChild(first-1).isText()) {
 68  2 first--;
 69    }
 70  5 while (last < parent.getChildCount()-1 && parent.getChild(last+1).isText()) {
 71  4 last++;
 72    }
 73  5 for (int i = first; i <= last; i++) {
 74  11 temp.add(parent.getChild(i));
 75    }
 76  5 contextNode = temp;
 77    }
 78  255 return new SingleObjectIterator(contextNode);
 79   
 80    }
 81   
 82   
 83  44 public Object getElementById(Object node, String id) {
 84   
 85  44 Node original;
 86  44 if (node instanceof ArrayList) {
 87  12 original = (Node) ((List) node).get(0);
 88    }
 89    else {
 90  32 original = (Node) node;
 91    }
 92  44 ParentNode parent;
 93  44 if (original.isElement() || original.isDocument()) {
 94  11 parent = (ParentNode) original;
 95    }
 96    else {
 97  33 parent = original.getParent();
 98    }
 99   
 100    // find highest parent node
 101  44 ParentNode high = parent;
 102  44 while (parent != null) {
 103  136 high = parent;
 104  136 parent = parent.getParent();
 105    }
 106   
 107    // Now search down from the highest point for the requested ID
 108  44 Element root;
 109  44 if (high.isDocument()) {
 110  39 root = ((Document) high).getRootElement();
 111    }
 112    else { // document fragment
 113  5 Node first = high.getChild(0);
 114  5 if (first.isElement()) {
 115  3 root = (Element) high.getChild(0);
 116    }
 117    else {
 118  2 return null;
 119    }
 120    }
 121   
 122  42 return findByID(root, id);
 123   
 124    }
 125   
 126   
 127    // ????remove recursion
 128  163 public static Element findByID(Element top, String id) {
 129   
 130  41 if (hasID(top, id)) return top;
 131    else {
 132  122 Elements children = top.getChildElements();
 133  122 for (int i = 0; i < children.size(); i++) {
 134  121 Element result = findByID(children.get(i), id);
 135  115 if (result != null) return result;
 136    }
 137    }
 138  7 return null;
 139   
 140    }
 141   
 142   
 143  163 private static boolean hasID(Element top, String id) {
 144   
 145  163 int count = top.getAttributeCount();
 146  163 for (int i = 0; i < count; i++) {
 147  79 Attribute a = top.getAttribute(i);
 148  79 if (Attribute.Type.ID == a.getType()) {
 149    // Do not need to fully normalize here
 150    // because if the value passed to the id() function
 151    // contains any spaces; then it is converted into a
 152    // search for multiple IDs, none of which have spaces
 153  41 return a.getValue().trim().equals(id);
 154    }
 155    }
 156  122 return false;
 157   
 158    }
 159   
 160   
 161  409 public String getNamespacePrefix(Object o) {
 162  409 Namespace ns = (Namespace) o;
 163  409 return ns.getPrefix();
 164    }
 165   
 166   
 167  52 public String getNamespaceStringValue(Object o) {
 168  52 Namespace ns = (Namespace) o;
 169  52 return ns.getValue();
 170    }
 171   
 172   
 173  289 public Iterator getNamespaceAxisIterator(Object contextNode) {
 174   
 175  289 try {
 176  289 Element element = (Element) contextNode;
 177    // ???? can probably avoid this list copy
 178  184 Map bindings = element.getNamespacePrefixesInScope();
 179  184 Iterator iterator = bindings.entrySet().iterator();
 180  184 List result = new ArrayList(bindings.size()+1);
 181  184 result.add(new Namespace("xml",
 182    "http://www.w3.org/XML/1998/namespace", element));
 183   
 184  184 while (iterator.hasNext()) {
 185  365 Map.Entry binding = (Map.Entry) iterator.next();
 186  365 String prefix = (String) binding.getKey();
 187  365 String uri = (String) binding.getValue();
 188  365 if (! "".equals(prefix) || ! "".equals(uri)) {
 189  236 Namespace ns = new Namespace(prefix, uri, element);
 190  236 result.add(ns);
 191    }
 192    }
 193  184 return result.iterator();
 194    }
 195    catch (ClassCastException ex) {
 196  105 return JaxenConstants.EMPTY_ITERATOR;
 197    }
 198   
 199    }
 200   
 201   
 202  86 public Iterator getParentAxisIterator(Object contextNode) {
 203   
 204  86 Node parent = (Node) getParentNode(contextNode);
 205  2 if (parent == null) return JaxenConstants.EMPTY_ITERATOR;
 206  84 else return new SingleObjectIterator(parent);
 207   
 208    }
 209   
 210   
 211  410 public Object getDocumentNode(Object o) {
 212   
 213  410 Node node = (Node) o;
 214  410 return node.getRoot();
 215   
 216    }
 217   
 218   
 219  0 public Object getDocument(String url) throws FunctionCallException {
 220  0 throw new FunctionCallException("document() function not supported");
 221    }
 222   
 223  4541 public Iterator getAttributeAxisIterator(Object contextNode) {
 224   
 225  4541 try {
 226  4541 Element element = (Element) contextNode;
 227  4495 return element.attributeIterator();
 228    }
 229    catch (ClassCastException ex) {
 230  46 return JaxenConstants.EMPTY_ITERATOR;
 231    }
 232   
 233    }
 234   
 235   
 236  164700 public Iterator getChildAxisIterator(Object o) {
 237   
 238  164700 if (o instanceof ParentNode) {
 239  56369 return new ChildIterator((ParentNode) o);
 240    }
 241    else {
 242  108331 return JaxenConstants.EMPTY_ITERATOR;
 243    }
 244   
 245    }
 246   
 247   
 248  2834 public Iterator getFollowingSiblingAxisIterator(Object o) {
 249   
 250  2834 Node start;
 251  2834 if (o instanceof ArrayList) {
 252  108 List list = (ArrayList) o;
 253  108 start = (Node) list.get(list.size()-1);
 254    }
 255    else {
 256  2726 start = (Node) o;
 257    }
 258  2834 ParentNode parent = start.getParent();
 259  1 if (parent == null) return JaxenConstants.EMPTY_ITERATOR;
 260  2833 int startPos = parent.indexOf(start) + 1;
 261  2833 return new ChildIterator(parent, startPos);
 262   
 263    }
 264   
 265   
 266  44091 public Object getParentNode(Object o) {
 267   
 268  44091 Node n;
 269  44091 if (o instanceof ArrayList) {
 270  496 n = (Node) ((List) o).get(0);
 271    }
 272    else {
 273  43595 n = (Node) o;
 274    }
 275  44091 return n.getParent();
 276   
 277    }
 278   
 279   
 280  9 public String getTextStringValue(Object o) {
 281   
 282  9 List texts = (List) o;
 283  9 if (texts.size() == 1) {
 284  6 return ((Text) texts.get(0)).getValue();
 285    }
 286    else {
 287  3 StringBuffer result = new StringBuffer();
 288  3 Iterator iterator = texts.iterator();
 289  3 while (iterator.hasNext()) {
 290  9 Text text = (Text) iterator.next();
 291  9 result.append(text.getValue());
 292    }
 293  3 return result.toString();
 294    }
 295   
 296    }
 297   
 298   
 299    private static class ChildIterator implements Iterator {
 300   
 301    private final ParentNode parent;
 302   
 303    private int xomIndex = 0;
 304    private final int xomCount;
 305   
 306  56369 ChildIterator(ParentNode parent) {
 307  56369 this.parent = parent;
 308  56369 this.xomCount = parent.getChildCount();
 309    }
 310   
 311   
 312  2833 ChildIterator(ParentNode parent, int startNode) {
 313  2833 this.parent = parent;
 314  2833 this.xomIndex = startNode;
 315  2833 this.xomCount = parent.getChildCount();
 316    }
 317   
 318   
 319  382685 public boolean hasNext() {
 320   
 321  382685 for (int i = xomIndex; i < xomCount; i++) {
 322  325935 Node next = parent.getChild(i);
 323  325935 if (next.isText()) {
 324  214690 if (! ((Text) next).isEmpty()) {
 325  214671 return true;
 326    }
 327    }
 328  111245 else return true;
 329    }
 330  56769 return false;
 331   
 332    }
 333   
 334   
 335  175211 public Object next() {
 336   
 337  175211 Object result;
 338  175211 Node next = parent.getChild(xomIndex++);
 339  175211 if (next.isText()) {
 340  113675 Text t = (Text) next;
 341    // Is this an empty text node?
 342  113675 boolean empty = t.isEmpty();
 343  113675 List texts = new ArrayList(1);
 344  113675 texts.add(t);
 345  113675 while (xomIndex < xomCount) {
 346  60528 Node nextText = parent.getChild(xomIndex);
 347  60501 if (! nextText.isText()) break;
 348  27 xomIndex++;
 349  27 texts.add(nextText);
 350  27 if (empty) {
 351  8 if (! ((Text) nextText).isEmpty()) {
 352  6 empty = false;
 353    }
 354    }
 355    }
 356    // need to make sure at least one of these texts is non-empty
 357  4 if (empty) return next();
 358  113671 else result = texts;
 359    }
 360  61536 else if (next.isDocType()) {
 361  21 return next();
 362    }
 363    else {
 364  61515 result = next;
 365    }
 366  175186 return result;
 367   
 368    }
 369   
 370  0 public void remove() {
 371  0 throw new UnsupportedOperationException();
 372    }
 373   
 374    }
 375   
 376   
 377    private static class NamedChildIterator implements Iterator {
 378   
 379    private final ParentNode parent;
 380   
 381    private int index = -1;
 382    private final int xomCount;
 383    private Element next;
 384    private final String localName;
 385    private final String URI;
 386   
 387  6268 NamedChildIterator(ParentNode parent, String localName, String prefix, String namespaceURI) {
 388  6268 this.parent = parent;
 389  6268 this.xomCount = parent.getChildCount();
 390  6268 this.localName = localName;
 391  6235 if (namespaceURI == null) this.URI = "";
 392  33 else this.URI = namespaceURI;
 393   
 394  6268 findNext();
 395    }
 396   
 397  9415 private void findNext() {
 398   
 399  9415 while (++index < xomCount) {
 400  26705 Node next = parent.getChild(index);
 401  26705 if (next.isElement()) {
 402  10801 Element element = (Element) next;
 403  10801 String elementNamespace = element.getNamespaceURI();
 404  10801 if (elementNamespace.equals(URI)) {
 405    // I don't need to worry about the prefix here because XPath only iterates
 406    // by local name and namespace URI. The prefix doesn't matter.
 407    // This does assume that this class is non-public.
 408  10776 if (element.getLocalName().equals(localName)) {
 409  3147 this.next = element;
 410  3147 return;
 411    }
 412    }
 413    }
 414    }
 415  6268 next = null;
 416    }
 417   
 418  10396 public boolean hasNext() {
 419  10396 return next != null;
 420    }
 421   
 422   
 423  3147 public Object next() {
 424   
 425  0 if (next == null) throw new NoSuchElementException(); // Correct? Yes. Necessary????
 426  3147 Object result = next;
 427  3147 findNext();
 428  3147 return result;
 429    }
 430   
 431  0 public void remove() {
 432  0 throw new UnsupportedOperationException();
 433    }
 434   
 435    }
 436   
 437   
 438  46741 public String getElementNamespaceUri(Object element) {
 439  46741 return ((Element) element).getNamespaceURI();
 440    }
 441   
 442   
 443    // In Jaxen, name means the local name only
 444  46972 public String getElementName(Object element) {
 445  46972 return ((Element) element).getLocalName();
 446    }
 447   
 448  827 public String getElementQName(Object element) {
 449  827 return ((Element) element).getQualifiedName();
 450    }
 451   
 452   
 453  87 public String getAttributeNamespaceUri(Object attr) {
 454  87 Attribute attribute = (Attribute) attr;
 455  87 return attribute.getNamespaceURI();
 456    }
 457   
 458   
 459    // In Jaxen, name means the local name only
 460  948 public String getAttributeName(Object attr) {
 461  948 Attribute attribute = (Attribute) attr;
 462  948 return attribute.getLocalName();
 463    }
 464   
 465   
 466  2 public String getAttributeQName(Object attr) {
 467  2 Attribute attribute = (Attribute) attr;
 468  2 return attribute.getQualifiedName();
 469    }
 470   
 471  5 public String getProcessingInstructionData(Object o) {
 472  5 ProcessingInstruction pi = (ProcessingInstruction) o;
 473  5 return pi.getValue();
 474    }
 475   
 476   
 477  9 public String getProcessingInstructionTarget(Object o) {
 478  9 ProcessingInstruction pi = (ProcessingInstruction) o;
 479  9 return pi.getTarget();
 480    }
 481   
 482   
 483  6268 public boolean isDocument(Object object) {
 484  6268 return object instanceof Document || object instanceof DocumentFragment;
 485    }
 486   
 487   
 488  149810 public boolean isElement(Object object) {
 489  149810 return object instanceof Element;
 490    }
 491   
 492   
 493  12927 public boolean isAttribute(Object object) {
 494  12927 return object instanceof Attribute;
 495    }
 496   
 497   
 498  12032 public boolean isNamespace(Object object) {
 499  12032 return object instanceof Namespace;
 500    }
 501   
 502   
 503  5605 public boolean isComment(Object object) {
 504  5605 return object instanceof Comment;
 505    }
 506   
 507   
 508  100551 public boolean isText(Object object) {
 509    // ???? hack: need to use a separate special subclass of ArrayList I can identify.
 510    // But may not be necessary since this is not a public API. I don't
 511    // think there's any way to get a different ArrayList into this method.
 512  100551 if (object instanceof ArrayList) {
 513  88355 Iterator iterator = ((List) object).iterator();
 514  88355 while (iterator.hasNext()) {
 515  259 if (! (iterator.next() instanceof Text)) return false;
 516    }
 517  88096 return true;
 518    }
 519  12196 return false;
 520    }
 521   
 522   
 523  5577 public boolean isProcessingInstruction(Object object) {
 524  5577 return object instanceof ProcessingInstruction;
 525    }
 526   
 527   
 528  4 public String getCommentStringValue(Object comment) {
 529  4 return ((Comment) comment).getValue();
 530    }
 531   
 532   
 533  271 public String getElementStringValue(Object element) {
 534  271 return ((Element) element).getValue();
 535    }
 536   
 537   
 538  477 public String getAttributeStringValue(Object attribute) {
 539  477 return ((Attribute) attribute).getValue();
 540    }
 541   
 542   
 543  0 public XPath parseXPath(String expression) throws JaxenException {
 544  0 return new JaxenConnector(expression);
 545    }
 546   
 547   
 548  16061 public Iterator getChildAxisIterator(Object parent, String localName, String namespacePrefix, String namespaceURI)
 549    throws UnsupportedAxisException {
 550   
 551  16061 if (parent instanceof ParentNode) {
 552  6268 return new NamedChildIterator((ParentNode) parent, localName, namespacePrefix, namespaceURI);
 553    }
 554  9793 return JaxenConstants.EMPTY_ITERATOR;
 555   
 556    }
 557   
 558   
 559  1537 public Iterator getAttributeAxisIterator(Object contextNode, String localName, String namespacePrefix, String namespaceURI)
 560    throws UnsupportedAxisException {
 561   
 562    // I don't need to worry about the prefix here because XPath only iterates
 563    // by local name and namespace URI. The prefix doesn't matter.
 564    // This does assume that this class is non-public.
 565  1537 try {
 566  1537 Element element = (Element) contextNode;
 567  1515 Attribute result = null;
 568  1515 if (namespaceURI == null) {
 569  1511 result = element.getAttribute(localName);
 570    }
 571    else {
 572  4 result = element.getAttribute(localName, namespaceURI);
 573    }
 574   
 575  985 if (result == null) return JaxenConstants.EMPTY_ITERATOR;
 576   
 577  530 return new SingleObjectIterator(result);
 578    }
 579    catch (ClassCastException ex) {
 580  22 return JaxenConstants.EMPTY_ITERATOR;
 581    }
 582   
 583    }
 584   
 585   
 586    }