/** * Get n'th attribute (DOM NamedNodeMap method). In this implementation we number the attributes * as follows: 0 - the xmlns:xml namespace declaration 1-n further namespace declarations n+1... * "real" attribute declarations */ public Node item(int index) { if (index < 0) { return null; } if (index == 0) { NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, NamespaceConstant.XML_NAMESPACE_CODE, 0); return NodeOverNodeInfo.wrap(nn); } int nscount = getNumberOfNamespaces(); if (index < nscount) { int[] buffer = new int[8]; int[] nsList = parent.getDeclaredNamespaces(buffer); int nscode = nsList[index - 1]; NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, nscode, index); return NodeOverNodeInfo.wrap(nn); } int pos = 0; int attNr = (index - nscount); AxisIterator atts = parent.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo) atts.next(); if (att == null) { return null; } if (pos == attNr) { return NodeOverNodeInfo.wrap(att); } pos++; } }
/** Get named attribute (DOM NamedNodeMap method) */ public Node getNamedItem(String name) { if (name.equals("xmlns")) { int[] nsarray = parent.getDeclaredNamespaces(null); for (int i = 0; i < nsarray.length; i++) { if (nsarray[i] == -1) { return null; } else if (((nsarray[i] >> 16) & 0xffff) == 0) { NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, nsarray[i], i + 1); return NodeOverNodeInfo.wrap(nn); } } return null; } else if (name.startsWith("xmlns:")) { String prefix = name.substring(6); if (prefix.equals("xml")) { NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, NamespaceConstant.XML_CODE, 0); return NodeOverNodeInfo.wrap(nn); } int[] buffer = new int[8]; int[] nsarray = parent.getDeclaredNamespaces(buffer); for (int i = 0; i < nsarray.length; i++) { if (nsarray[i] == -1) { return null; } else if (prefix.equals(parent.getNamePool().getPrefixFromNamespaceCode(nsarray[i]))) { NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, nsarray[i], i + 1); return NodeOverNodeInfo.wrap(nn); } } return null; } else { AxisIterator atts = parent.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo) atts.next(); if (att == null) { return null; } if (name.equals(att.getDisplayName())) { return NodeOverNodeInfo.wrap(att); } } } }
/** Get named attribute (DOM NamedNodeMap method) */ public Node getNamedItemNS(String uri, String localName) { if (uri == null) { uri = ""; } if (NamespaceConstant.XMLNS.equals(uri)) { return getNamedItem("xmlns:" + localName); } if (uri.equals("") && localName.equals("xmlns")) { return getNamedItem("xmlns"); } AxisIterator atts = parent.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo) atts.next(); if (att == null) { return null; } if (uri.equals(att.getURI()) && localName.equals(att.getLocalPart())) { return NodeOverNodeInfo.wrap(att); } } }
/** * Convert an XPath value to an object in this object model. If the supplied value can be * converted to an object in this model, of the specified class, then the conversion should be * done and the resulting object returned. If the value cannot be converted, the method should * return null. Note that the supplied class might be a List, in which case the method should * inspect the contents of the Value to see whether they belong to this object model. * * @throws XPathException if the target class is explicitly associated with this object model, but * the supplied value cannot be converted to the appropriate class */ public Object convertXPathValueToObject(Value value, Class target, XPathContext context) throws XPathException { // We accept the object if (a) the target class is Node, Node[], or NodeList, // or (b) the supplied object is a node, or sequence of nodes, that wrap DOM nodes, // provided that the target class is Object or a collection class boolean requireDOM = (Node.class.isAssignableFrom(target) || (target == NodeList.class) || (target.isArray() && Node.class.isAssignableFrom(target.getComponentType()))); // Note: we allow the declared type of the method argument to be a subclass of Node. If the // actual // node supplied is the wrong kind of node, this will result in a Java exception. boolean allowDOM = (target == Object.class || target.isAssignableFrom(ArrayList.class) || target.isAssignableFrom(HashSet.class) || (target.isArray() && target.getComponentType() == Object.class)); if (!(requireDOM || allowDOM)) { return null; } List nodes = new ArrayList(20); SequenceIterator iter = value.iterate(context); while (true) { Item item = iter.next(); if (item == null) { break; } if (item instanceof VirtualNode) { Object o = ((VirtualNode) item).getUnderlyingNode(); if (o instanceof Node) { nodes.add(o); } else { if (requireDOM) { DynamicError err = new DynamicError( "Extension function required class " + target.getName() + "; supplied value of class " + item.getClass().getName() + " could not be converted"); throw err; } ; } } else if (requireDOM) { if (item instanceof NodeInfo) { nodes.add(NodeOverNodeInfo.wrap((NodeInfo) item)); } else { DynamicError err = new DynamicError( "Extension function required class " + target.getName() + "; supplied value of class " + item.getClass().getName() + " could not be converted"); throw err; } } else { return null; // DOM Nodes are not actually required; let someone else try the conversion } } if (nodes.size() == 0 && !requireDOM) { return null; // empty sequence supplied - try a different mapping } if (Node.class.isAssignableFrom(target)) { if (nodes.size() != 1) { DynamicError err = new DynamicError( "Extension function requires a single DOM Node" + "; supplied value contains " + nodes.size() + " nodes"); throw err; } return nodes.get(0); // could fail if the node is of the wrong kind } else if (target == NodeList.class) { return new DOMNodeList(nodes); } else if (target.isArray() && target.getComponentType() == Node.class) { Node[] array = new Node[nodes.size()]; nodes.toArray(array); return array; } else if (target.isAssignableFrom(ArrayList.class)) { return nodes; } else if (target.isAssignableFrom(HashSet.class)) { return new HashSet(nodes); } else { // after all this work, give up return null; } }