public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { if (context.getProfiler().isEnabled()) { context.getProfiler().start(this); context .getProfiler() .message( this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies())); if (contextSequence != null) context .getProfiler() .message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence); if (contextItem != null) context .getProfiler() .message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence()); } Sequence seq; Sequence result; if (contextItem != null) contextSequence = contextItem.toSequence(); /* if (contextSequence == null || contextSequence.isEmpty()) result = Sequence.EMPTY_SEQUENCE; */ // If we have one argument, we take it into account if (getSignature().getArgumentCount() > 0) seq = getArgument(0).eval(contextSequence, contextItem); // Otherwise, we take the context sequence and we iterate over it else seq = contextSequence; if (seq == null) throw new XPathException(this, "XPDY0002: Undefined context item"); if (seq.isEmpty()) // Bloody specs ! result = StringValue.EMPTY_STRING; else { Item item = seq.itemAt(0); if (!Type.subTypeOf(item.getType(), Type.NODE)) throw new XPathException( this, "XPTY0004: item is not a node; got '" + Type.getTypeName(item.getType()) + "'"); // TODO : how to improve performance ? Node n = ((NodeValue) item).getNode(); if (n instanceof QNameable) result = new StringValue(((QNameable) n).getQName().getStringValue()); else result = StringValue.EMPTY_STRING; } if (context.getProfiler().isEnabled()) context.getProfiler().end(this, "", result); return result; }
private static String serialize(DBBroker broker, Item item) throws SAXException, XPathException { Serializer serializer = broker.getSerializer(); serializer.reset(); String value; if (Type.subTypeOf(item.getType(), Type.NODE)) { value = serializer.serialize((NodeValue) item); } else { value = item.getStringValue(); } return value; }
@Override public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException { NodeImpl report = null; try { // Only match documents that match these URLs List<String> toBeMatchedURIs = new ArrayList<>(); Sequence pathSeq = getArgumentCount() == 2 ? args[0] : contextSequence; if (pathSeq == null) return Sequence.EMPTY_SEQUENCE; // Get first agument, these are the documents / collections to search in for (SequenceIterator i = pathSeq.iterate(); i.hasNext(); ) { String path; Item item = i.nextItem(); if (Type.subTypeOf(item.getType(), Type.NODE)) { if (((NodeValue) item).isPersistentSet()) { path = ((NodeProxy) item).getDocument().getURI().toString(); } else { path = item.getStringValue(); } } else { path = item.getStringValue(); } toBeMatchedURIs.add(path); } // Get second argument, this is the query String query; if (getArgumentCount() == 1) query = args[0].itemAt(0).getStringValue(); else query = args[1].itemAt(0).getStringValue(); // Get the lucene worker LuceneIndexWorker index = (LuceneIndexWorker) context.getBroker().getIndexController().getWorkerByIndexId(LuceneIndex.ID); // Perform search report = index.search(context, toBeMatchedURIs, query); } catch (XPathException ex) { // Log and rethrow logger.error(ex); throw ex; } // Return list of matching files. return report; }
/* (non-Javadoc) * @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[], org.exist.xquery.value.Sequence) */ public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException { if (context.getProfiler().isEnabled()) { context.getProfiler().start(this); context .getProfiler() .message( this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies())); if (contextSequence != null) context .getProfiler() .message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence); } Sequence result; // return 0 if the argument sequence is empty // TODO : return empty sequence ? if (args[0].isEmpty()) result = IntegerValue.ZERO; else { int count = 0; for (SequenceIterator i = args[0].iterate(); i.hasNext(); ) { Item next = i.nextItem(); if (Type.subTypeOf(next.getType(), Type.NODE)) { NodeValue nv = (NodeValue) next; if (nv.getImplementationType() != NodeValue.PERSISTENT_NODE) throw new XPathException( getASTNode(), getName() + " cannot be applied to in-memory nodes."); NodeProxy np = (NodeProxy) nv; Match match = np.getMatches(); while (match != null) { if (match.getNodeId().isDescendantOrSelfOf(np.getNodeId())) { count += match.getFrequency(); } match = match.getNextMatch(); } } } result = new IntegerValue(count); } if (context.getProfiler().isEnabled()) context.getProfiler().end(this, "", result); return result; }
/** * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, * java.lang.String, org.xml.sax.Attributes) */ public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { // save accumulated character content if (inModification && charBuf.length() > 0) { // String normalized = charBuf.toString(); final String normalized = preserveWhitespace ? charBuf.toString() : charBuf.getNormalizedString(FastStringBuffer.SUPPRESS_BOTH); if (normalized.length() > 0) { final Text text = doc.createTextNode(charBuf.toString()); if (stack.isEmpty()) { // LOG.debug("appending text to fragment: " + text.getData()); contents.add(text); } else { final Element last = stack.peek(); last.appendChild(text); } } charBuf.setLength(0); } if (namespaceURI.equals(XUPDATE_NS)) { String select = null; if (localName.equals(MODIFICATIONS)) { startModifications(atts); return; } else if (localName.equals(VARIABLE)) { // variable declaration startVariableDecl(atts); return; } else if (IF.equals(localName)) { if (inModification) { throw new SAXException("xupdate:if is not allowed inside a modification"); } select = atts.getValue("test"); final Conditional cond = new Conditional(broker, documentSet, select, namespaces, variables); cond.setAccessContext(accessCtx); conditionals.push(cond); return; } else if (VALUE_OF.equals(localName)) { if (!inModification) { throw new SAXException("xupdate:value-of is not allowed outside a modification"); } } else if (APPEND.equals(localName) || INSERT_BEFORE.equals(localName) || INSERT_AFTER.equals(localName) || REMOVE.equals(localName) || RENAME.equals(localName) || UPDATE.equals(localName) || REPLACE.equals(localName)) { if (inModification) { throw new SAXException("nested modifications are not allowed"); } select = atts.getValue("select"); if (select == null) { throw new SAXException(localName + " requires a select attribute"); } doc = builder.newDocument(); contents = new NodeListImpl(); inModification = true; } else if ((ELEMENT.equals(localName) || ATTRIBUTE.equals(localName) || TEXT.equals(localName) || PROCESSING_INSTRUCTION.equals(localName) || COMMENT.equals(localName))) { if (!inModification) { throw new SAXException("creation elements are only allowed inside " + "a modification"); } charBuf.setLength(0); } else { throw new SAXException("Unknown XUpdate element: " + qName); } // start a new modification section if (APPEND.equals(localName)) { final String child = atts.getValue("child"); modification = new Append(broker, documentSet, select, child, namespaces, variables); } else if (UPDATE.equals(localName)) { modification = new Update(broker, documentSet, select, namespaces, variables); } else if (INSERT_BEFORE.equals(localName)) { modification = new Insert(broker, documentSet, select, Insert.INSERT_BEFORE, namespaces, variables); } else if (INSERT_AFTER.equals(localName)) { modification = new Insert(broker, documentSet, select, Insert.INSERT_AFTER, namespaces, variables); } else if (REMOVE.equals(localName)) { modification = new Remove(broker, documentSet, select, namespaces, variables); } else if (RENAME.equals(localName)) { modification = new Rename(broker, documentSet, select, namespaces, variables); } else if (REPLACE.equals(localName)) { modification = new Replace(broker, documentSet, select, namespaces, variables); } // process commands for node creation else if (ELEMENT.equals(localName)) { String name = atts.getValue("name"); if (name == null) { throw new SAXException("element requires a name attribute"); } final int p = name.indexOf(':'); String namespace = null; String prefix = ""; if (p != Constants.STRING_NOT_FOUND) { prefix = name.substring(0, p); if (name.length() == p + 1) { throw new SAXException("illegal prefix in qname: " + name); } name = name.substring(p + 1); namespace = atts.getValue("namespace"); if (namespace == null) { namespace = (String) namespaces.get(prefix); } if (namespace == null) { throw new SAXException("no namespace defined for prefix " + prefix); } } Element elem; if (namespace != null && namespace.length() > 0) { elem = doc.createElementNS(namespace, name); elem.setPrefix(prefix); } else { elem = doc.createElement(name); } if (stack.isEmpty()) { contents.add(elem); } else { final Element last = stack.peek(); last.appendChild(elem); } this.setWhitespaceHandling((Element) stack.push(elem)); } else if (ATTRIBUTE.equals(localName)) { final String name = atts.getValue("name"); if (name == null) { throw new SAXException("attribute requires a name attribute"); } final int p = name.indexOf(':'); String namespace = null; if (p != Constants.STRING_NOT_FOUND) { final String prefix = name.substring(0, p); if (name.length() == p + 1) { throw new SAXException("illegal prefix in qname: " + name); } namespace = atts.getValue("namespace"); if (namespace == null) { namespace = (String) namespaces.get(prefix); } if (namespace == null) { throw new SAXException("no namespace defined for prefix " + prefix); } } Attr attrib = namespace != null && namespace.length() > 0 ? doc.createAttributeNS(namespace, name) : doc.createAttribute(name); if (stack.isEmpty()) { for (int i = 0; i < contents.getLength(); i++) { final Node n = contents.item(i); String ns = n.getNamespaceURI(); final String nname = ns == null ? n.getNodeName() : n.getLocalName(); if (ns == null) { ns = ""; } // check for duplicate attributes if (n.getNodeType() == Node.ATTRIBUTE_NODE && nname.equals(name) && ns.equals(namespace)) { throw new SAXException( "The attribute " + attrib.getNodeName() + " cannot be specified twice"); } } contents.add(attrib); } else { final Element last = (Element) stack.peek(); if (namespace != null && last.hasAttributeNS(namespace, name) || namespace == null && last.hasAttribute(name)) { throw new SAXException( "The attribute " + attrib.getNodeName() + " cannot be specified " + "twice on the same element"); } if (namespace != null) { last.setAttributeNodeNS(attrib); } else { last.setAttributeNode(attrib); } } inAttribute = true; currentNode = attrib; // process value-of } else if (VALUE_OF.equals(localName)) { select = atts.getValue("select"); if (select == null) { throw new SAXException("value-of requires a select attribute"); } final Sequence seq = processQuery(select); if (LOG.isDebugEnabled()) { LOG.debug("Found " + seq.getItemCount() + " items for value-of"); } Item item; try { for (final SequenceIterator i = seq.iterate(); i.hasNext(); ) { item = i.nextItem(); if (Type.subTypeOf(item.getType(), Type.NODE)) { final Node node = NodeSetHelper.copyNode(doc, ((NodeValue) item).getNode()); if (stack.isEmpty()) { contents.add(node); } else { final Element last = (Element) stack.peek(); last.appendChild(node); } } else { final String value = item.getStringValue(); characters(value.toCharArray(), 0, value.length()); } } } catch (final XPathException e) { throw new SAXException(e.getMessage(), e); } } } else if (inModification) { final Element elem = namespaceURI != null && namespaceURI.length() > 0 ? doc.createElementNS(namespaceURI, qName) : doc.createElement(qName); Attr a; for (int i = 0; i < atts.getLength(); i++) { final String name = atts.getQName(i); final String nsURI = atts.getURI(i); if (name.startsWith("xmlns")) { // Why are these showing up? They are supposed to be stripped out? } else { a = nsURI != null ? doc.createAttributeNS(nsURI, name) : doc.createAttribute(name); a.setValue(atts.getValue(i)); if (nsURI != null) { elem.setAttributeNodeNS(a); } else { elem.setAttributeNode(a); } } } if (stack.isEmpty()) { contents.add(elem); } else { final Element last = (Element) stack.peek(); last.appendChild(elem); } this.setWhitespaceHandling((Element) stack.push(elem)); } }
/** Add a sequence item to the node set. The item has to be a subtype of node. */ public void add(Item item) throws XPathException { if (!Type.subTypeOf(item.getType(), Type.NODE)) throw new XPathException("item has wrong type"); add((NodeProxy) item); }
private boolean deepEquals(Item a, Item b, Collator collator) { try { final boolean aAtomic = Type.subTypeOf(a.getType(), Type.ATOMIC); final boolean bAtomic = Type.subTypeOf(b.getType(), Type.ATOMIC); if (aAtomic || bAtomic) { if (!aAtomic || !bAtomic) return false; try { AtomicValue av = (AtomicValue) a; AtomicValue bv = (AtomicValue) b; if (Type.subTypeOf(av.getType(), Type.NUMBER) && Type.subTypeOf(bv.getType(), Type.NUMBER)) { // or if both values are NaN if (((NumericValue) a).isNaN() && ((NumericValue) b).isNaN()) return true; } return ValueComparison.compareAtomic( collator, av, bv, Constants.TRUNC_NONE, Constants.EQ); } catch (XPathException e) { return false; } } // assert Type.subTypeOf(a.getType(), Type.NODE); // assert Type.subTypeOf(b.getType(), Type.NODE); if (a.getType() != b.getType()) return false; NodeValue nva = (NodeValue) a, nvb = (NodeValue) b; if (nva == nvb) return true; try { // Don't use this shortcut for in-memory nodes since the symbol table is ignored. if (nva.getImplementationType() != NodeValue.IN_MEMORY_NODE && nva.equals(nvb)) return true; // shortcut! } catch (XPathException e) { // apparently incompatible values, do manual comparison } Node na, nb; switch (a.getType()) { case Type.DOCUMENT: // NodeValue.getNode() doesn't seem to work for document nodes na = nva instanceof Node ? (Node) nva : ((NodeProxy) nva).getDocument(); nb = nvb instanceof Node ? (Node) nvb : ((NodeProxy) nvb).getDocument(); return compareContents(na, nb); case Type.ELEMENT: na = nva.getNode(); nb = nvb.getNode(); return compareElements(na, nb); case Type.ATTRIBUTE: na = nva.getNode(); nb = nvb.getNode(); return compareNames(na, nb) && safeEquals(na.getNodeValue(), nb.getNodeValue()); case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: na = nva.getNode(); nb = nvb.getNode(); return safeEquals(na.getNodeName(), nb.getNodeName()) && safeEquals(nva.getStringValue(), nvb.getStringValue()); case Type.TEXT: case Type.COMMENT: return safeEquals(nva.getStringValue(), nvb.getStringValue()); default: { logger.error("unexpected item type " + Type.getTypeName(a.getType())); throw new RuntimeException("unexpected item type " + Type.getTypeName(a.getType())); } } } catch (XPathException e) { logger.error(e.getMessage()); e.printStackTrace(); return false; } }