From: Wolfgang M. M. <wol...@us...> - 2004-09-21 14:42:14
|
Update of /cvsroot/exist/eXist-1.0/src/org/exist/xupdate In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5047/src/org/exist/xupdate Modified Files: XUpdateProcessor.java Modification.java Added Files: Conditional.java Log Message: * Added missing support for xupdate:if * Fixed xupdate:value-of * Prohibit duplicate attributes Index: XUpdateProcessor.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/xupdate/XUpdateProcessor.java,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -d -r1.25 -r1.26 *** XUpdateProcessor.java 12 Sep 2004 09:25:22 -0000 1.25 --- XUpdateProcessor.java 21 Sep 2004 14:42:04 -0000 1.26 *************** *** 29,33 **** --- 29,36 ---- import org.exist.xquery.parser.XQueryParser; import org.exist.xquery.parser.XQueryTreeParser; + import org.exist.xquery.value.Item; + import org.exist.xquery.value.NodeValue; import org.exist.xquery.value.Sequence; + import org.exist.xquery.value.SequenceIterator; import org.exist.xquery.value.Type; import org.w3c.dom.Attr; *************** *** 36,40 **** import org.w3c.dom.Element; import org.w3c.dom.Node; - import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; --- 39,42 ---- *************** *** 67,79 **** --- 69,87 ---- private boolean inModification = false; private boolean inAttribute = false; + private Modification modification = null; private DocumentBuilder builder; private Document doc; + private Stack stack = new Stack(); private Node currentNode = null; private DBBroker broker; private DocumentSet documentSet; + private List modifications = new ArrayList(); + private Stack conditionals = new Stack(); + private FastStringBuffer charBuf = new FastStringBuffer(6, 15, 5); + private Map variables = new TreeMap(); private Map namespaces = new HashMap(10); *************** *** 191,227 **** if (namespaceURI.equals(XUPDATE_NS)) { if (localName.equals("modifications")) { ! String version = atts.getValue("version"); ! if (version == null) ! throw new SAXException( ! "version attribute is required for " ! + "element modifications"); ! if (!version.equals("1.0")) ! throw new SAXException( ! "Version " ! + version ! + " of XUpdate " ! + "not supported."); return; } - String select = null; // variable declaration if (localName.equals("variable")) { ! select = atts.getValue("select"); ! if (select == null) ! throw new SAXException("variable declaration requires a select attribute"); ! String name = atts.getValue("name"); ! if (name == null) ! throw new SAXException("variable declarations requires a name attribute"); ! createVariable(name, select); return; } ! ! if (localName.equals("append") ! || localName.equals("insert-before") ! || localName.equals("insert-after") ! || localName.equals("remove") ! || localName.equals("rename") ! || localName.equals("update")) { if (inModification) throw new SAXException("nested modifications are not allowed"); --- 199,226 ---- if (namespaceURI.equals(XUPDATE_NS)) { if (localName.equals("modifications")) { ! startModifications(atts); return; } // variable declaration if (localName.equals("variable")) { ! startVariableDecl(atts); return; } ! ! String select = null; ! if ("if".equals(localName)) { ! if (inModification) ! throw new SAXException("xupdate:if is not allowed inside a modification"); ! select = atts.getValue("test"); ! Conditional cond = new Conditional(broker, documentSet, select, namespaces); ! conditionals.push(cond); ! return; ! } else if ("append".equals(localName) ! || "insert-before".equals(localName) ! || "insert-after".equals(localName) ! || "remove".equals(localName) ! || "rename".equals(localName) ! || "update".equals(localName)) { if (inModification) throw new SAXException("nested modifications are not allowed"); *************** *** 234,242 **** inModification = true; } else if ( ! (localName.equals("element") ! || localName.equals("attribute") ! || localName.equals("text") ! || localName.equals("processing-instruction") ! || localName.equals("comment")) && (!inModification)) throw new SAXException( --- 233,241 ---- inModification = true; } else if ( ! ("element".equals(localName) ! || "attribute".equals(localName) ! || "text".equals(localName) ! || "processing-instruction".equals(localName) ! || "comment".equals(localName)) && (!inModification)) throw new SAXException( *************** *** 245,266 **** // start a new modification section ! if (localName.equals("append")) { String child = atts.getValue("child"); modification = new Append(broker, documentSet, select, child, namespaces); ! } else if (localName.equals("update")) modification = new Update(broker, documentSet, select, namespaces); ! else if (localName.equals("insert-before")) modification = new Insert(broker, documentSet, select, Insert.INSERT_BEFORE, namespaces); ! else if (localName.equals("insert-after")) modification = new Insert(broker, documentSet, select, Insert.INSERT_AFTER, namespaces); ! else if (localName.equals("remove")) modification = new Remove(broker, documentSet, select, namespaces); ! else if (localName.equals("rename")) modification = new Rename(broker, documentSet, select, namespaces); // process commands for node creation ! else if (localName.equals("element")) { String name = atts.getValue("name"); if (name == null) --- 244,265 ---- // start a new modification section ! if ("append".equals(localName)) { String child = atts.getValue("child"); modification = new Append(broker, documentSet, select, child, namespaces); ! } else if ("update".equals(localName)) modification = new Update(broker, documentSet, select, namespaces); ! else if ("insert-before".equals(localName)) modification = new Insert(broker, documentSet, select, Insert.INSERT_BEFORE, namespaces); ! else if ("insert-after".equals(localName)) modification = new Insert(broker, documentSet, select, Insert.INSERT_AFTER, namespaces); ! else if ("remove".equals(localName)) modification = new Remove(broker, documentSet, select, namespaces); ! else if ("rename".equals(localName)) modification = new Rename(broker, documentSet, select, namespaces); // process commands for node creation ! else if ("element".equals(localName)) { String name = atts.getValue("name"); if (name == null) *************** *** 290,294 **** } stack.push(elem); ! } else if (localName.equals("attribute")) { String name = atts.getValue("name"); if (name == null) --- 289,293 ---- } stack.push(elem); ! } else if ("attribute".equals(localName)) { String name = atts.getValue("name"); if (name == null) *************** *** 308,315 **** } Attr attrib = doc.createAttributeNS(namespace, name); ! if (stack.isEmpty()) contents.add(attrib); ! else { Element last = (Element) stack.peek(); last.setAttributeNode(attrib); } --- 307,326 ---- } Attr attrib = doc.createAttributeNS(namespace, name); ! if (stack.isEmpty()) { ! for(int i = 0; i < contents.getLength(); i++) { ! Node n = contents.item(i); ! String ns = n.getNamespaceURI(); ! if(ns == null) ns = ""; ! if(n.getNodeType() == Node.ATTRIBUTE_NODE && ! n.getLocalName().equals(name) && ! ns.equals(namespace)) ! throw new SAXException("The attribute " + attrib.getNodeName() + " cannot be specified twice"); ! } contents.add(attrib); ! } else { Element last = (Element) stack.peek(); + if(last.getAttributeNS(namespace, name) != null) + throw new SAXException("The attribute " + attrib.getNodeName() + " cannot be specified " + + "twice on the same element"); last.setAttributeNode(attrib); } *************** *** 318,342 **** // process value-of ! } else if (localName.equals("value-of")) { select = atts.getValue("select"); if (select == null) throw new SAXException("value-of requires a select attribute"); ! List nodes; ! if (select.startsWith("$")) { ! nodes = (List) variables.get(select); ! if (nodes == null) ! throw new SAXException( ! "variable " + select + " not found"); ! } else ! nodes = processQuery(select); ! LOG.debug("found " + nodes.size() + " nodes for value-of"); ! Node node; ! for (Iterator i = nodes.iterator(); i.hasNext();) { ! node = XMLUtil.copyNode(doc, (Node) i.next()); ! if (stack.isEmpty()) ! contents.add(node); ! else { ! Element last = (Element) stack.peek(); ! last.appendChild(node); } } --- 329,356 ---- // 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"); ! Sequence seq = processQuery(select); ! LOG.debug("Found " + seq.getLength() + " items for value-of"); ! Item item; ! for (SequenceIterator i = seq.iterate(); i.hasNext();) { ! item = i.nextItem(); ! if(Type.subTypeOf(item.getType(), Type.NODE)) { ! Node node = XMLUtil.copyNode(doc, ((NodeValue)item).getNode()); ! if (stack.isEmpty()) ! contents.add(node); ! else { ! Element last = (Element) stack.peek(); ! last.appendChild(node); ! } ! } else { ! try { ! String value = item.getStringValue(); ! characters(value.toCharArray(), 0, value.length()); ! } catch(XPathException e) { ! throw new SAXException(e.getMessage(), e); ! } } } *************** *** 360,363 **** --- 374,401 ---- } + private void startVariableDecl(Attributes atts) throws SAXException { + String select = atts.getValue("select"); + if (select == null) + throw new SAXException("variable declaration requires a select attribute"); + String name = atts.getValue("name"); + if (name == null) + throw new SAXException("variable declarations requires a name attribute"); + createVariable(name, select); + } + + private void startModifications(Attributes atts) throws SAXException { + String version = atts.getValue("version"); + if (version == null) + throw new SAXException( + "version attribute is required for " + + "element modifications"); + if (!version.equals("1.0")) + throw new SAXException( + "Version " + + version + + " of XUpdate " + + "not supported."); + } + /** * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) *************** *** 379,388 **** charBuf.setLength(0); } ! if (namespaceURI.equals(XUPDATE_NS)) { ! if (localName.equals("element")) { stack.pop(); ! } else if (localName.equals("attribute")) inAttribute = false; ! if (localName.equals("append") || localName.equals("update") || localName.equals("remove") --- 417,429 ---- charBuf.setLength(0); } ! if (XUPDATE_NS.equals(namespaceURI)) { ! if ("if".equals(localName)) { ! Conditional cond = (Conditional) conditionals.pop(); ! modifications.add(cond); ! } else if (localName.equals("element")) { stack.pop(); ! } else if (localName.equals("attribute")) { inAttribute = false; ! } else if (localName.equals("append") || localName.equals("update") || localName.equals("remove") *************** *** 392,396 **** inModification = false; modification.setContent(contents); ! modifications.add(modification); modification = null; } --- 433,442 ---- inModification = false; modification.setContent(contents); ! if(!conditionals.isEmpty()) { ! Conditional cond = (Conditional) conditionals.peek(); ! cond.addModification(modification); ! } else { ! modifications.add(modification); ! } modification = null; } *************** *** 467,476 **** throws SAXException { LOG.debug("creating variable " + name + " as " + select); ! List result = processQuery(select); ! LOG.debug("found " + result.size() + " for variable " + name); ! variables.put('$' + name, result); } ! private List processQuery(String select) throws SAXException { try { XQueryContext context = new XQueryContext(broker); --- 513,522 ---- throws SAXException { LOG.debug("creating variable " + name + " as " + select); ! Sequence result = processQuery(select); ! LOG.debug("found " + result.getLength() + " for variable " + name); ! variables.put(name, result); } ! private Sequence processQuery(String select) throws SAXException { try { XQueryContext context = new XQueryContext(broker); *************** *** 483,486 **** --- 529,536 ---- (String) entry.getValue()); } + for (Iterator i = variables.entrySet().iterator(); i.hasNext(); ) { + entry = (Map.Entry) i.next(); + context.declareVariable(entry.getKey().toString(), entry.getValue()); + } XQueryLexer lexer = new XQueryLexer(context, new StringReader(select)); XQueryParser parser = new XQueryParser(lexer); *************** *** 501,513 **** Sequence seq = expr.eval(null, null); ! if (!(seq.getItemType() == Type.NODE)) ! throw new SAXException( ! "select expression should evaluate to a" + "node-set"); ! NodeList set = (NodeList)seq; ! ArrayList out = new ArrayList(set.getLength()); ! for (int i = 0; i < set.getLength(); i++) { ! out.add(set.item(i)); ! } ! return out; } catch (RecognitionException e) { LOG.warn("error while creating variable", e); --- 551,555 ---- Sequence seq = expr.eval(null, null); ! return seq; } catch (RecognitionException e) { LOG.warn("error while creating variable", e); Index: Modification.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/xupdate/Modification.java,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** Modification.java 12 Sep 2004 09:25:23 -0000 1.31 --- Modification.java 21 Sep 2004 14:42:04 -0000 1.32 *************** *** 116,126 **** context.setExclusiveMode(true); context.setStaticallyKnownDocuments(docs); ! Map.Entry entry; ! for (Iterator i = namespaces.entrySet().iterator(); i.hasNext();) { ! entry = (Map.Entry) i.next(); ! context.declareNamespace( ! (String) entry.getKey(), ! (String) entry.getValue()); ! } XQueryLexer lexer = new XQueryLexer(context, new StringReader(selectStmt)); XQueryParser parser = new XQueryParser(lexer); --- 116,120 ---- context.setExclusiveMode(true); context.setStaticallyKnownDocuments(docs); ! declareNamespaces(context); XQueryLexer lexer = new XQueryLexer(context, new StringReader(selectStmt)); XQueryParser parser = new XQueryParser(lexer); *************** *** 156,159 **** --- 150,166 ---- /** + * @param context + */ + protected void declareNamespaces(XQueryContext context) { + Map.Entry entry; + for (Iterator i = namespaces.entrySet().iterator(); i.hasNext();) { + entry = (Map.Entry) i.next(); + context.declareNamespace( + (String) entry.getKey(), + (String) entry.getValue()); + } + } + + /** * Acquire a lock on all documents processed by this modification. * We have to avoid that node positions change during the --- NEW FILE: Conditional.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier (wol...@ex...) * and others (see http://exist-db.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: Conditional.java,v 1.1 2004/09/21 14:42:04 wolfgang_m Exp $ */ package org.exist.xupdate; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.exist.EXistException; import org.exist.dom.DocumentSet; import org.exist.security.PermissionDeniedException; import org.exist.storage.DBBroker; import org.exist.util.LockException; import org.exist.xquery.CompiledXQuery; import org.exist.xquery.XPathException; import org.exist.xquery.XQuery; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.Sequence; /** * @author wolf */ public class Conditional extends Modification { private List modifications = new ArrayList(5); /** * @param broker * @param docs * @param selectStmt * @param namespaces */ public Conditional(DBBroker broker, DocumentSet docs, String selectStmt, Map namespaces) { super(broker, docs, selectStmt, namespaces); } public void addModification(Modification mod) { modifications.add(mod); } /* (non-Javadoc) * @see org.exist.xupdate.Modification#process() */ public long process() throws PermissionDeniedException, LockException, EXistException, XPathException { LOG.debug("Processing xupdate:if ..."); XQuery xquery = broker.getXQueryService(); XQueryContext context = xquery.newContext(); context.setBackwardsCompatibility(true); context.setStaticallyKnownDocuments(docs); declareNamespaces(context); CompiledXQuery compiled = xquery.compile(context, new StringReader(selectStmt)); Sequence seq = xquery.execute(compiled, null); if(seq.effectiveBooleanValue()) { long mods = 0; for (int i = 0; i < modifications.size(); i++) { mods += ((Modification)modifications.get(i)).process(); broker.flush(); } LOG.debug(mods + " modifications processed."); return mods; } else return 0; } /* (non-Javadoc) * @see org.exist.xupdate.Modification#getName() */ public String getName() { return "if"; } } |