package org.basex.query.up.primitives; import org.basex.data.Data; import org.basex.data.MemData; import org.basex.query.QueryException; import org.basex.query.item.ANode; import org.basex.query.item.FTxt; import org.basex.query.item.NodeType; import org.basex.query.item.QNm; import org.basex.query.iter.NodeCache; import org.basex.query.up.NamePool; import org.basex.query.util.DataBuilder; import org.basex.util.InputInfo; import org.basex.util.TokenBuilder; import org.basex.util.Util; import org.basex.util.list.ObjList; /** * Abstract update primitive which holds a copy of nodes to be inserted. * * @author BaseX Team 2005-12, BSD License * @author Lukas Kircher */ public abstract class NodeCopy extends StructuralUpdate { /** Nodes to be inserted. */ ObjList<NodeCache> insert = new ObjList<NodeCache>(1); /** Final copy of insertion nodes. */ MemData md; /** Number of insert operations (initialized by {@link #prepare}). */ int size; /** * Constructor. * @param t type * @param p pre * @param d data * @param i input info * @param nc node copy */ NodeCopy(final PrimitiveType t, final int p, final Data d, final InputInfo i, final NodeCache nc) { super(t, p, d, i); insert.add(nc); } /** * Prepares this update primitive before execution. This includes i.e. the * preparation of insertion sequences. * @throws QueryException exception during preparation of data */ @SuppressWarnings("unused") public void prepare() throws QueryException { // build main memory representation of nodes to be copied md = new MemData(data); final NodeCache seq = new NodeCache(); for(int i = 0; i < insert.size(); i++) { final NodeCache nc = insert.get(i); for(ANode n; (n = nc.next()) != null;) { seq.add(n); size++; } // save memory insert.set(i, null); } insert = null; // text nodes still need to be merged. two adjacent iterators may // lead to two adjacent text nodes new DataBuilder(md).build(mergeNodeCacheText(seq)); } /** * Adds top entries from the temporary data instance to the name pool, * which is used for finding duplicate attributes and namespace conflicts. * @param pool name pool */ final void add(final NamePool pool) { for(int p = 0; p < md.meta.size; ++p) { final int k = md.kind(p); if(k != Data.ATTR && k != Data.ELEM || md.parent(p, k) > -1) continue; final int u = md.uri(p, k); final QNm qnm = new QNm(md.name(p, k)); if(u != 0) qnm.uri(md.nspaces.uri(u)); pool.add(qnm, ANode.type(k)); } } /** * Merges all adjacent text nodes in the given sequence. * @param n iterator * @return iterator with merged text nodes */ private static NodeCache mergeNodeCacheText(final NodeCache n) { final NodeCache s = new NodeCache(); ANode i = n.next(); while(i != null) { if(i.type == NodeType.TXT) { final TokenBuilder tb = new TokenBuilder(); while(i != null && i.type == NodeType.TXT) { tb.add(i.string()); i = n.next(); } s.add(new FTxt(tb.finish())); } else { s.add(i); i = n.next(); } } return s; } @Override public final int size() { return size; } @Override public String toString() { return Util.name(this) + '[' + targetNode() + ", " + size() + " ops]"; } }