From: Wolfgang M. M. <wol...@us...> - 2004-06-27 21:10:48
|
Update of /cvsroot/exist/eXist-1.0/src/org/exist/xquery In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8241/src/org/exist/xquery Modified Files: XQueryContext.java ElementConstructor.java TextConstructor.java Added Files: DynamicAttributeConstructor.java DynamicTextConstructor.java DocumentConstructor.java DynamicPIConstructor.java DynamicCommentConstructor.java Log Message: Added support for dynamic node constructors in XQuery. --- NEW FILE: DynamicAttributeConstructor.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier * wol...@ex... * 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: DynamicAttributeConstructor.java,v 1.1 2004/06/27 21:10:06 wolfgang_m Exp $ */ package org.exist.xquery; import org.exist.dom.QName; import org.exist.memtree.DocumentImpl; import org.exist.memtree.MemTreeBuilder; import org.exist.memtree.NodeImpl; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceIterator; /** * Represents a dynamic attribute constructor. The implementation differs from * AttributeConstructor as the evaluation is not controlled by the surrounding * element. The attribute name as well as its value are only determined at evaluation time, * not at compile time. * * @author wolf */ public class DynamicAttributeConstructor extends NodeConstructor { private Expression qnameExpr; private Expression valueExpr; /** * @param context */ public DynamicAttributeConstructor(XQueryContext context) { super(context); } public void setNameExpr(Expression expr) { this.qnameExpr = new Atomize(context, expr); } public void setValueExpr(Expression expr) { this.valueExpr = new Atomize(context, expr); } /* (non-Javadoc) * @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item) */ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { MemTreeBuilder builder = context.getDocumentBuilder(); context.proceed(this, builder); Sequence nameSeq = qnameExpr.eval(contextSequence, contextItem); if(nameSeq.getLength() != 1) throw new XPathException(getASTNode(), "The name expression should evaluate to a single value"); QName qn = QName.parse(context, nameSeq.getStringValue()); String value; Sequence valueSeq = valueExpr.eval(contextSequence, contextItem); if(valueSeq.getLength() == 0) value = ""; else { StringBuffer buf = new StringBuffer(); for(SequenceIterator i = valueSeq.iterate(); i.hasNext(); ) { Item next = i.nextItem(); buf.append(next.getStringValue()); if(i.hasNext()) buf.append(' '); } value = buf.toString(); } int nodeNr = builder.addAttribute(qn, value); NodeImpl node = ((DocumentImpl)builder.getDocument()).getAttribute(nodeNr); return node; } /* (non-Javadoc) * @see org.exist.xquery.Expression#pprint() */ public String pprint() { StringBuffer buf = new StringBuffer(); buf.append("attribute { "); buf.append(qnameExpr.pprint()); buf.append(" } { "); buf.append(valueExpr.pprint()); buf.append(" }"); return buf.toString(); } } Index: XQueryContext.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/xquery/XQueryContext.java,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** XQueryContext.java 2 Jun 2004 11:34:36 -0000 1.17 --- XQueryContext.java 27 Jun 2004 21:10:06 -0000 1.18 *************** *** 657,662 **** public void popDocumentContext() { ! if (!fragmentStack.isEmpty()) builder = (MemTreeBuilder) fragmentStack.pop(); } --- 657,663 ---- public void popDocumentContext() { ! if (!fragmentStack.isEmpty()) { builder = (MemTreeBuilder) fragmentStack.pop(); + } } --- NEW FILE: DocumentConstructor.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier * wol...@ex... * 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: DocumentConstructor.java,v 1.1 2004/06/27 21:10:06 wolfgang_m Exp $ */ package org.exist.xquery; import org.exist.memtree.MemTreeBuilder; import org.exist.memtree.NodeImpl; import org.exist.memtree.Receiver; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceIterator; import org.exist.xquery.value.Type; import org.xml.sax.SAXException; /** * Implements a dynamic document constructor. Creates a new * document node with its own node identity. * * @author wolf */ public class DocumentConstructor extends NodeConstructor { private Expression content; /** * @param context */ public DocumentConstructor(XQueryContext context, Expression contentExpr) { super(context); this.content = contentExpr; } /* (non-Javadoc) * @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item) */ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { System.out.println(content.pprint()); Sequence contentSeq = content.eval(contextSequence, contextItem); context.pushDocumentContext(); MemTreeBuilder builder = context.getDocumentBuilder(); Receiver receiver = new Receiver(builder); if(contentSeq.getLength() == 0) return builder.getDocument(); try { StringBuffer buf = null; SequenceIterator i = contentSeq.iterate(); Item next = i.nextItem(); while(next != null) { context.proceed(this, builder); if(next.getType() == Type.ATTRIBUTE || next.getType() == Type.NAMESPACE || next.getType() == Type.DOCUMENT) throw new XPathException(getASTNode(), "Found a node of type " + Type.getTypeName(next.getType()) + " inside a document constructor"); // if item is an atomic value, collect the string values of all // following atomic values and seperate them by a space. if (Type.subTypeOf(next.getType(), Type.ATOMIC)) { if(buf == null) buf = new StringBuffer(); else if (buf.length() > 0) buf.append(' '); buf.append(next.getStringValue()); next = i.nextItem(); // if item is a node, flush any collected character data and // copy the node to the target doc. } else if (Type.subTypeOf(next.getType(), Type.NODE)) { if (buf != null && buf.length() > 0) { receiver.characters(buf); buf.setLength(0); } next.copyTo(context.getBroker(), receiver); next = i.nextItem(); } } // flush remaining character data if (buf != null && buf.length() > 0) receiver.characters(buf); } catch(SAXException e) { throw new XPathException(getASTNode(), "Encountered SAX exception while processing document constructor: " + pprint()); } NodeImpl node = builder.getDocument(); context.popDocumentContext(); return node; } /* (non-Javadoc) * @see org.exist.xquery.Expression#pprint() */ public String pprint() { StringBuffer buf = new StringBuffer(); buf.append("document { ").append(content.pprint()).append(" }"); return buf.toString(); } } Index: TextConstructor.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/xquery/TextConstructor.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** TextConstructor.java 28 May 2004 10:54:12 -0000 1.3 --- TextConstructor.java 27 Jun 2004 21:10:06 -0000 1.4 *************** *** 31,35 **** /** ! * Constructor for text nodes. * * @author wolf --- 31,35 ---- /** ! * Direct constructor for text nodes. * * @author wolf --- NEW FILE: DynamicCommentConstructor.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier * wol...@ex... * 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: DynamicCommentConstructor.java,v 1.1 2004/06/27 21:10:06 wolfgang_m Exp $ */ package org.exist.xquery; import org.exist.memtree.DocumentImpl; import org.exist.memtree.MemTreeBuilder; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceIterator; /** * Implements a dynamic comment constructor. Contrary to {@link org.exist.xquery.CommentConstructor}, * the character content of a DynamicCommentConstructor is determined only at evaluation time. * * @author wolf */ public class DynamicCommentConstructor extends NodeConstructor { private Expression content; /** * @param context */ public DynamicCommentConstructor(XQueryContext context, Expression contentExpr) { super(context); this.content = new Atomize(context, contentExpr); } /* (non-Javadoc) * @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item) */ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { Sequence contentSeq = content.eval(contextSequence, contextItem); if(contentSeq.getLength() == 0) return Sequence.EMPTY_SEQUENCE; MemTreeBuilder builder = context.getDocumentBuilder(); context.proceed(this, builder); StringBuffer buf = new StringBuffer(); for(SequenceIterator i = contentSeq.iterate(); i.hasNext(); ) { context.proceed(this, builder); Item next = i.nextItem(); if(buf.length() > 0) buf.append(' '); buf.append(next.toString()); } int nodeNr = builder.comment(buf.toString()); return ((DocumentImpl)builder.getDocument()).getNode(nodeNr); } /* (non-Javadoc) * @see org.exist.xquery.Expression#pprint() */ public String pprint() { StringBuffer buf = new StringBuffer(); buf.append("comment { ").append(content.pprint()).append(" }"); return buf.toString(); } } --- NEW FILE: DynamicTextConstructor.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier * wol...@ex... * 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: DynamicTextConstructor.java,v 1.1 2004/06/27 21:10:06 wolfgang_m Exp $ */ package org.exist.xquery; import org.exist.memtree.DocumentImpl; import org.exist.memtree.MemTreeBuilder; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceIterator; /** * Implements a dynamic text constructor. Contrary to {@link org.exist.xquery.TextConstructor}, * the character content of a DynamicTextConstructor is determined only at evaluation time. * * @author wolf */ public class DynamicTextConstructor extends NodeConstructor { private Expression content; /** * @param context */ public DynamicTextConstructor(XQueryContext context, Expression contentExpr) { super(context); this.content = new Atomize(context, contentExpr); } /* (non-Javadoc) * @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item) */ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { Sequence contentSeq = content.eval(contextSequence, contextItem); if(contentSeq.getLength() == 0) return Sequence.EMPTY_SEQUENCE; MemTreeBuilder builder = context.getDocumentBuilder(); context.proceed(this, builder); StringBuffer buf = new StringBuffer(); for(SequenceIterator i = contentSeq.iterate(); i.hasNext(); ) { context.proceed(this, builder); Item next = i.nextItem(); if(buf.length() > 0) buf.append(' '); buf.append(next.toString()); } int nodeNr = builder.characters(buf); return ((DocumentImpl)builder.getDocument()).getNode(nodeNr); } /* (non-Javadoc) * @see org.exist.xquery.Expression#pprint() */ public String pprint() { StringBuffer buf = new StringBuffer(); buf.append("text { ").append(content.pprint()).append(" }"); return buf.toString(); } } --- NEW FILE: DynamicPIConstructor.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier * wol...@ex... * 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: DynamicPIConstructor.java,v 1.1 2004/06/27 21:10:06 wolfgang_m Exp $ */ package org.exist.xquery; import org.exist.dom.QName; import org.exist.memtree.DocumentImpl; import org.exist.memtree.MemTreeBuilder; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.SequenceIterator; import org.exist.xquery.value.Type; /** * Dynamic constructor for processing instruction nodes. * * @author wolf */ public class DynamicPIConstructor extends NodeConstructor { private Expression name; private Expression content; /** * @param context */ public DynamicPIConstructor(XQueryContext context) { super(context); } public void setNameExpr(Expression nameExpr) { this.name = nameExpr; } public void setContentExpr(Expression contentExpr) { this.content = contentExpr; } /* (non-Javadoc) * @see org.exist.xquery.Expression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item) */ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { MemTreeBuilder builder = context.getDocumentBuilder(); context.proceed(this, builder); Sequence nameSeq = name.eval(contextSequence, contextItem); if(nameSeq.getLength() != 1) throw new XPathException(getASTNode(), "The name expression should evaluate to a single value"); Item nameItem = nameSeq.itemAt(0); if(!(nameItem.getType() == Type.STRING || nameItem.getType() == Type.QNAME)) throw new XPathException(getASTNode(), "The name expression should evaluate to a string or qname"); QName qn = QName.parse(context, nameSeq.getStringValue()); String value; Sequence contentSeq = content.eval(contextSequence, contextItem); if(contentSeq.getLength() == 0) value = ""; else { StringBuffer buf = new StringBuffer(); for(SequenceIterator i = contentSeq.iterate(); i.hasNext(); ) { context.proceed(this, builder); Item next = i.nextItem(); if(buf.length() > 0) buf.append(' '); buf.append(next.toString()); } value = buf.toString(); } int nodeNr = builder.processingInstruction(qn.getLocalName(), value); return ((DocumentImpl)builder.getDocument()).getNode(nodeNr); } /* (non-Javadoc) * @see org.exist.xquery.Expression#pprint() */ public String pprint() { StringBuffer buf = new StringBuffer(); buf.append("processing-instruction { ").append(name.pprint()); buf.append(" } { ").append(content.pprint()).append(" }"); return buf.toString(); } } Index: ElementConstructor.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/xquery/ElementConstructor.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** ElementConstructor.java 28 May 2004 10:54:12 -0000 1.4 --- ElementConstructor.java 27 Jun 2004 21:10:06 -0000 1.5 *************** *** 29,36 **** import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.xml.sax.helpers.AttributesImpl; /** ! * Constructor for element nodes. * * @author wolf --- 29,38 ---- import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; + import org.exist.xquery.value.StringValue; import org.xml.sax.helpers.AttributesImpl; /** ! * Constructor for element nodes. This class handles both, direct and dynamic ! * element constructors. * * @author wolf *************** *** 38,48 **** public class ElementConstructor extends NodeConstructor { ! private String qname; private PathExpr content = null; private AttributeConstructor attributes[] = null; public ElementConstructor(XQueryContext context, String qname) { super(context); ! this.qname = qname; } --- 40,54 ---- public class ElementConstructor extends NodeConstructor { ! private Expression qnameExpr; private PathExpr content = null; private AttributeConstructor attributes[] = null; + public ElementConstructor(XQueryContext context) { + super(context); + } + public ElementConstructor(XQueryContext context, String qname) { super(context); ! this.qnameExpr = new LiteralValue(context, new StringValue(qname)); } *************** *** 51,54 **** --- 57,64 ---- } + public void setNameExpr(Expression expr) { + this.qnameExpr = new Atomize(context, expr); + } + public void addAttribute(AttributeConstructor attr) { if(attributes == null) { *************** *** 106,110 **** // create the element ! QName qn = QName.parse(context, qname); int nodeNr = builder.startElement(qn, attrs); // process element contents --- 116,124 ---- // create the element ! Sequence qnameSeq = qnameExpr.eval(contextSequence, contextItem); ! if(qnameSeq.getLength() != 1) ! throw new XPathException("Type error: the node name should evaluate to a single string"); ! QName qn = QName.parse(context, qnameSeq.getStringValue()); ! int nodeNr = builder.startElement(qn, attrs); // process element contents *************** *** 123,127 **** public String pprint() { StringBuffer buf = new StringBuffer(); ! buf.append('<').append(qname); if(attributes != null) { AttributeConstructor attr; --- 137,141 ---- public String pprint() { StringBuffer buf = new StringBuffer(); ! buf.append('<').append(qnameExpr.pprint()); if(attributes != null) { AttributeConstructor attr; *************** *** 136,140 **** buf.append('>'); buf.append(content.pprint()); ! buf.append("</").append(qname.toString()).append('>'); } return buf.toString(); --- 150,154 ---- buf.append('>'); buf.append(content.pprint()); ! buf.append("</").append(qnameExpr.pprint()).append('>'); } return buf.toString(); |