/**
   * Returns atomic text node merging operations if necessary for the given node PRE and its right
   * neighbor PRE+1.
   *
   * @param a node PRE value
   * @param d target data reference
   * @return list of text merging operations
   */
  private AtomicUpdateList necessaryMerges(final int a, final Data d) {
    final AtomicUpdateList mergeTwoNodes = new AtomicUpdateList(d);
    final int s = d.meta.size;
    final int b = a + 1;
    // don't leave table
    if (a >= s || b >= s || a < 0 || b < 0) return mergeTwoNodes;
    // only merge texts
    if (d.kind(a) != Data.TEXT || d.kind(b) != Data.TEXT) return mergeTwoNodes;
    // only merge neighboring texts
    if (d.parent(a, Data.TEXT) != d.parent(b, Data.TEXT)) return mergeTwoNodes;

    mergeTwoNodes.addDelete(b);
    mergeTwoNodes.addUpdateValue(a, Data.TEXT, Token.concat(d.text(a, true), d.text(b, true)));

    return mergeTwoNodes;
  }
 /**
  * Calculates the new distance value for the given node.
  *
  * @param preAfter the current PRE value of the node (after structural updates have been applied)
  * @return new distance for the given node
  */
 private int calculateNewDistance(final int preAfter) {
   final int kind = data.kind(preAfter);
   final int distanceBefore = data.dist(preAfter, kind);
   final int preBefore = calculatePreValue(preAfter, true);
   final int parentBefore = preBefore - distanceBefore;
   final int parentAfter = calculatePreValue(parentBefore, false);
   return preAfter - parentAfter;
 }
Exemple #3
0
 /**
  * Returns the value for the specified pre value.
  *
  * @param pre pre value
  * @return item value
  */
 byte[] getValue(final int pre) {
   final Data data = plotData.context.data;
   final int limit = pre + data.size(pre, Data.ELEM);
   for (int p = pre; p < limit; ++p) {
     final int kind = data.kind(p);
     if ((kind == Data.ELEM && tag || kind == Data.ATTR && !tag) && attrID == data.name(p))
       return data.atom(p);
   }
   return EMPTY;
 }
  /**
   * Updates distances to restore parent-child relationships that have been invalidated by
   * structural updates.
   *
   * <p>Each structural update (insert/delete) leads to a shift of higher PRE values. This
   * invalidates parent-child relationships. Distances are only updated after all structural updates
   * have been carried out to make sure each node (that has to be updated) is only touched once.
   */
  public void updateDistances() {
    accumulatePreValueShifts();
    final IntSet alreadyUpdatedNodes = new IntSet();

    for (final BasicUpdate update : updStructural) {
      int newPreOfAffectedNode = update.preOfAffectedNode + update.accumulatedShifts;

      /* Update distance for the affected node and all following siblings of nodes
       * on the ancestor-or-self axis. */
      while (newPreOfAffectedNode < data.meta.size) {
        if (alreadyUpdatedNodes.contains(newPreOfAffectedNode)) break;
        data.dist(
            newPreOfAffectedNode,
            data.kind(newPreOfAffectedNode),
            calculateNewDistance(newPreOfAffectedNode));
        alreadyUpdatedNodes.add(newPreOfAffectedNode);
        newPreOfAffectedNode += data.size(newPreOfAffectedNode, data.kind(newPreOfAffectedNode));
      }
    }
  }
Exemple #5
0
 /** Inserts an attribute with namespace. */
 @Test
 public void insertAttributeWithNs() {
   create(1);
   query("insert node attribute { QName('ns', 'pref:local') } { } into /*");
   final Data data = context.data();
   assertEquals(false, data.nsFlag(0));
   assertEquals(true, data.nsFlag(1));
   assertEquals(false, data.nsFlag(2));
   assertEquals(0, data.uriId(1, data.kind(1)));
   assertEquals(1, data.uriId(2, data.kind(2)));
   assertEquals("ns", string(data.nspaces.uri(1)));
 }
Exemple #6
0
  /**
   * Creates an item iterator for the given XML fragment.
   *
   * @param xml fragment
   * @param frag fragment flag
   * @return iterator
   */
  private ItemCache toIter(final String xml, final boolean frag) {
    final ItemCache it = new ItemCache();
    try {
      String str = frag ? "<X>" + xml + "</X>" : xml;
      final Data d = CreateDB.xml(IO.get(str), context);

      for (int p = frag ? 2 : 0; p < d.meta.size; p += d.size(p, d.kind(p)))
        it.add(new DBNode(d, p));
    } catch (final IOException ex) {
      return new ItemCache(new Item[] {Str.get(Long.toString(System.nanoTime()))}, 1);
    }
    return it;
  }
Exemple #7
0
 @Override
 public void execute(final GUI gui) {
   // skip operation for root context
   final Context ctx = gui.context;
   if (ctx.root()) return;
   // check if all nodes are document nodes
   boolean doc = true;
   final Data data = ctx.data();
   for (final int pre : ctx.current().pres) doc &= data.kind(pre) == Data.DOC;
   if (doc) {
     // if yes, jump to database root
     ctx.update();
     gui.notify.context(ctx.current(), false, null);
   } else {
     // otherwise, jump to parent nodes
     gui.execute(new Cs(".."));
   }
 }
  /**
   * Removes superfluous update operations. If a node T is deleted or replaced, all updates on the
   * descendant axis of T can be left out as they won't affect the database after all.
   *
   * <p>Superfluous updates can have a minimum PRE value of pre(T)+1 and a maximum PRE value of
   * pre(T)+size(T).
   *
   * <p>An update with location pre(T)+size(T) can only be removed if the update is an atomic insert
   * and the inserted node is then part of the subtree of T.
   */
  public void optimize() {
    if (opt) return;

    check();
    // traverse from lowest to highest PRE value
    int i = updStructural.size() - 1;
    while (i >= 0) {
      final BasicUpdate u = updStructural.get(i);
      // If this update can lead to superfluous updates ...
      if (u.destructive()) {
        // we determine the lowest and highest PRE values of a superfluous update
        final int pre = u.location;
        final int fol = pre + data.size(pre, data.kind(pre));
        i--;
        // and have a look at the next candidate
        while (i >= 0) {
          final BasicUpdate desc = updStructural.get(i);
          final int descpre = desc.location;
          // if the candidate operates on the subtree of T and inserts a node ...
          if (descpre <= fol
              && (desc instanceof Insert || desc instanceof InsertAttr)
              && desc.parent() >= pre
              && desc.parent() < fol) {
            // it is removed.
            updStructural.remove(i--);

            // Other updates (not inserting a node) that operate on the subtree of T can
            // only have a PRE value that is smaller than the following PRE of T
          } else if (descpre < fol) {
            // these we delete.
            updStructural.remove(i--);

            // Else there's nothing to delete
          } else break;
        }
      } else i--;
    }
    opt = true;
  }
  /**
   * Writes the entry for the specified pre value to the table.
   *
   * @param t table reference
   * @param data data reference
   * @param p node to be printed
   */
  private static void table(final Table t, final Data data, final int p) {
    final int k = data.kind(p);
    final TokenList tl = new TokenList();
    tl.add(p);
    tl.add(p - data.parent(p, k));
    tl.add(data.size(p, k));
    tl.add(data.attSize(p, k));
    final int u = data.uri(p, k);
    if (data.nsFlag(p)) tl.add("+" + u);
    else tl.add(u);
    tl.add(TABLEKINDS[k]);

    byte[] cont = null;
    if (k == Data.ELEM) {
      cont = data.name(p, k);
    } else if (k == Data.ATTR) {
      cont =
          new TokenBuilder(data.name(p, k)).add(ATT1).add(data.text(p, false)).add(ATT2).finish();
    } else {
      cont = data.text(p, true);
    }
    tl.add(replace(chop(cont, 64), '\n', ' '));
    t.contents.add(tl);
  }
  @Override
  public void paintComponent(final Graphics g) {
    super.paintComponent(g);

    // skip if view is unavailable
    if (tdata.rows == null) return;

    gui.painting = true;
    g.setFont(GUIConstants.font);

    final int w = getWidth() - scroll.getWidth();
    final int h = getHeight();
    final int fsz = gui.gprop.num(GUIProp.FONTSIZE);

    final Context context = tdata.context;
    final Data data = context.data();
    final int focus = gui.context.focused;
    final int rfocus = tdata.getRoot(data, focus);
    int mpos = 0;

    final int nCols = tdata.cols.length;
    final int nRows = tdata.rows.size();
    final int rowH = tdata.rowH;

    final TableIterator ti = new TableIterator(data, tdata);
    final TokenBuilder[] tb = new TokenBuilder[nCols];
    for (int i = 0; i < nCols; ++i) tb[i] = new TokenBuilder();

    focusedString = null;
    final Nodes marked = context.marked;
    int l = scroll.pos() / rowH - 1;
    int posY = -scroll.pos() + l * rowH;

    while (++l < nRows && marked != null) {
      // skip when all visible rows have been painted or if data has changed
      if (posY > h || l >= tdata.rows.size()) break;
      posY += rowH;

      final int pre = tdata.rows.get(l);
      while (mpos < marked.size() && marked.list[mpos] < pre) ++mpos;

      // draw line
      g.setColor(GUIConstants.color2);
      g.drawLine(0, posY + rowH - 1, w, posY + rowH - 1);
      g.setColor(Color.white);
      g.drawLine(0, posY + rowH, w, posY + rowH);

      // verify if current node is marked or focused
      final boolean rm = mpos < marked.size() && marked.list[mpos] == pre;
      final boolean rf = pre == rfocus;
      final int col = rm ? rf ? 5 : 4 : 3;
      if (rm || rf) {
        g.setColor(GUIConstants.color(col));
        g.fillRect(0, posY - 1, w, rowH);
        g.setColor(GUIConstants.color(col + 4));
        g.drawLine(0, posY - 1, w, posY - 1);
      }
      g.setColor(Color.black);

      // skip drawing of text during animation
      if (rowH < fsz) continue;

      // find all row contents
      ti.init(pre);
      int fcol = -1;
      while (ti.more()) {
        final int c = ti.col;
        if (ti.pre == focus || data.parent(ti.pre, data.kind(ti.pre)) == focus) fcol = c;

        // add content to column (skip too long contents)...
        if (tb[c].size() < 100) {
          if (tb[c].size() != 0) tb[c].add("; ");
          tb[c].add(data.text(ti.pre, ti.text));
        }
      }

      // add dots if content is too long
      for (final TokenBuilder t : tb) if (t.size() > 100) t.add(DOTS);

      // draw row contents
      byte[] focusStr = null;
      int fx = -1;
      double x = 1;
      for (int c = 0; c < nCols; ++c) {
        // draw single column
        final double cw = w * tdata.cols[c].width;
        final double ce = x + cw;

        if (ce != 0) {
          final byte[] str = tb[c].size() != 0 ? tb[c].finish() : null;
          if (str != null) {
            if (tdata.mouseX > x && tdata.mouseX < ce || fcol == c) {
              fx = (int) x;
              focusStr = str;
            }
            BaseXLayout.chopString(g, str, (int) x + 1, posY + 2, (int) cw - 4, fsz);
            tb[c].reset();
          }
        }
        x = ce;
      }

      // highlight focused entry
      if (rf || fcol != -1) {
        if (focusStr != null) {
          final int sw = BaseXLayout.width(g, focusStr) + 8;
          if (fx > w - sw - 2) fx = w - sw - 2;
          g.setColor(GUIConstants.color(col + 2));
          g.fillRect(fx - 2, posY, sw, rowH - 1);
          g.setColor(Color.black);
          BaseXLayout.chopString(g, focusStr, fx + 1, posY + 2, sw, fsz);

          // cache focused string
          focusedString = string(focusStr);
          final int i = focusedString.indexOf("; ");
          if (i != -1) focusedString = focusedString.substring(0, i);
        }
      }
    }
    gui.painting = false;
  }
Exemple #11
0
  /**
   * Optimizes the structures of a database.
   *
   * @param data data
   * @param enforceText enforce creation or deletion of text index
   * @param enforceAttr enforce creation or deletion of attribute index
   * @param enforceToken enforce creation or deletion of token index
   * @param enforceFt enforce creation or deletion of full-text index
   * @param cmd calling command instance (may be {@code null})
   * @throws IOException I/O Exception during index rebuild
   */
  public static void optimize(
      final Data data,
      final boolean enforceText,
      final boolean enforceAttr,
      final boolean enforceToken,
      final boolean enforceFt,
      final Optimize cmd)
      throws IOException {

    // initialize structural indexes
    final MetaData md = data.meta;
    if (!md.uptodate) {
      data.paths.init();
      data.elemNames.init();
      data.attrNames.init();
      md.dirty = true;

      final IntList pars = new IntList(), elms = new IntList();
      int n = 0;

      for (int pre = 0; pre < md.size; ++pre) {
        final byte kind = (byte) data.kind(pre);
        final int par = data.parent(pre, kind);
        while (!pars.isEmpty() && pars.peek() > par) {
          pars.pop();
          elms.pop();
        }

        final int level = pars.size();
        if (kind == Data.DOC) {
          data.paths.put(0, Data.DOC, level);
          pars.push(pre);
          elms.push(0);
          ++n;
        } else if (kind == Data.ELEM) {
          final int id = data.nameId(pre);
          data.elemNames.index(data.elemNames.key(id), null, true);
          data.paths.put(id, Data.ELEM, level);
          pars.push(pre);
          elms.push(id);
        } else if (kind == Data.ATTR) {
          final int id = data.nameId(pre);
          final byte[] val = data.text(pre, false);
          data.attrNames.index(data.attrNames.key(id), val, true);
          data.paths.put(id, Data.ATTR, level, val, md);
        } else {
          final byte[] val = data.text(pre, true);
          if (kind == Data.TEXT && level > 1) data.elemNames.index(elms.peek(), val);
          data.paths.put(0, kind, level, val, md);
        }
        if (cmd != null) cmd.pre = pre;
      }
      md.ndocs = n;
      md.uptodate = true;
    }

    // rebuild value indexes
    optimize(IndexType.TEXT, data, md.createtext, md.textindex, enforceText, cmd);
    optimize(IndexType.ATTRIBUTE, data, md.createattr, md.attrindex, enforceAttr, cmd);
    optimize(IndexType.TOKEN, data, md.createtoken, md.tokenindex, enforceToken, cmd);
    optimize(IndexType.FULLTEXT, data, md.createft, md.ftindex, enforceFt, cmd);
  }
 /**
  * Initializes the iterator.
  *
  * @param p root pre value
  */
 private void init(final int p) {
   final int k = data.kind(p);
   size = p + data.size(p, k);
   pre = p + data.attSize(p, k);
 }
Exemple #13
0
  @Override
  void drawRectangles(final Graphics g, final MapRects rects, final float scale) {
    // some additions to set up borders
    final MapRect l = view.layout.layout;
    l.x = (int) scale * l.x;
    l.y = (int) scale * l.y;
    l.w = (int) scale * l.w;
    l.h = (int) scale * l.h;
    final int ww = view.getWidth();
    final int hh = view.getWidth();

    final Data data = view.gui.context.data();
    final int fsz = GUIConstants.fontSize;

    final int off = gopts.get(GUIOptions.MAPOFFSETS);
    final int rs = rects.size;
    for (int ri = 0; ri < rs; ++ri) {
      // get rectangle information
      final MapRect r = rects.get(ri);
      final int pre = r.pre;

      // level 1: next context node, set marker pointer to 0
      final int lvl = r.level;

      final boolean full = r.w == ww && r.h == hh;
      Color col = color(rects, ri);
      final boolean mark = col != null;

      r.pos =
          view.gui.context.marked.ftpos != null
              ? view.gui.context.marked.ftpos.get(data, pre)
              : null;
      g.setColor(mark ? col : GUIConstants.color(lvl));

      if (r.w < l.x + l.w || r.h < l.y + l.h || off < 2 || ViewData.leaf(gopts, data, pre)) {
        g.fillRect(r.x, r.y, r.w, r.h);
      } else {
        // painting only border for non-leaf nodes..
        g.fillRect(r.x, r.y, l.x, r.h);
        g.fillRect(r.x, r.y, r.w, l.y);
        g.fillRect(r.x + r.w - l.w, r.y, l.w, r.h);
        g.fillRect(r.x, r.y + r.h - l.h, r.w, l.h);
      }

      if (!full) {
        col = mark ? GUIConstants.colormark3 : GUIConstants.color(lvl + 2);
        g.setColor(col);
        g.drawRect(r.x, r.y, r.w, r.h);
        col = mark ? GUIConstants.colormark4 : GUIConstants.color(Math.max(0, lvl - 2));
        g.setColor(col);
        g.drawLine(r.x + r.w, r.y, r.x + r.w, r.y + r.h);
        g.drawLine(r.x, r.y + r.h, r.x + r.w, r.y + r.h);
      }

      // skip drawing of string if there is no space
      if (r.w <= 3 || r.h < GUIConstants.fontSize) continue;

      r.x += 3;
      r.w -= 3;

      final int kind = data.kind(pre);
      if (kind == Data.ELEM || kind == Data.DOC) {
        g.setColor(Color.black);
        g.setFont(GUIConstants.font);
        BaseXLayout.chopString(g, ViewData.name(gopts, data, pre), r.x, r.y, r.w, fsz);
      } else {
        g.setColor(GUIConstants.color(r.level * 2 + 8));
        g.setFont(GUIConstants.mfont);
        final byte[] text = ViewData.content(data, pre, false);

        r.thumb = MapRenderer.calcHeight(g, r, text, fsz) >= r.h;
        if (r.thumb) {
          MapRenderer.drawThumbnails(g, r, text, fsz);
        } else {
          MapRenderer.drawText(g, r, text, fsz);
        }
      }
      r.x -= 3;
      r.w += 3;
    }
  }
 /**
  * Adds a replace atomic to the list.
  *
  * @param pre PRE value of the target node/update location
  * @param d insertion sequence data reference
  */
 public void addReplace(final int pre, final Data d) {
   final int oldsize = data.size(pre, data.kind(pre));
   final int newsize = d.meta.size;
   add(new Replace(pre, newsize - oldsize, pre + oldsize, d), true);
 }
 /**
  * Adds a delete atomic to the list.
  *
  * @param pre PRE value of the target node/update location
  */
 public void addDelete(final int pre) {
   final int k = data.kind(pre);
   final int s = data.size(pre, k);
   add(new Delete(pre, -s, pre + s), true);
 }
Exemple #16
0
  /**
   * Replaces parts of the database with the specified data instance.
   *
   * @param rpre pre value to be replaced
   * @param clip data clip
   */
  public final void replace(final int rpre, final DataClip clip) {
    meta.update();

    final int dsize = clip.size();
    final Data data = clip.data;

    final int rkind = kind(rpre);
    final int rsize = size(rpre, rkind);
    final int rpar = parent(rpre, rkind);
    final int diff = dsize - rsize;
    buffer(dsize);
    resources.replace(rpre, rsize, clip);

    if (meta.updindex) {
      // update index
      indexDelete(rpre, rsize);
      indexBegin();
    }

    for (int dpre = clip.start; dpre < clip.end; ++dpre) {
      final int dkind = data.kind(dpre);
      final int dpar = data.parent(dpre, dkind);
      final int pre = rpre + dpre - clip.start;
      final int dis = dpar >= 0 ? dpre - dpar : pre - rpar;

      switch (dkind) {
        case DOC:
          // add document
          doc(pre, data.size(dpre, dkind), data.text(dpre, true));
          meta.ndocs++;
          break;
        case ELEM:
          // add element
          byte[] nm = data.name(dpre, dkind);
          elem(
              dis,
              tagindex.index(nm, null, false),
              data.attSize(dpre, dkind),
              data.size(dpre, dkind),
              nspaces.uri(nm, true),
              false);
          break;
        case TEXT:
        case COMM:
        case PI:
          // add text
          text(pre, dis, data.text(dpre, true), dkind);
          break;
        case ATTR:
          // add attribute
          nm = data.name(dpre, dkind);
          attr(
              pre,
              dis,
              atnindex.index(nm, null, false),
              data.text(dpre, false),
              nspaces.uri(nm, false),
              false);
          break;
      }
    }

    if (meta.updindex) {
      indexEnd();
      // update ID -> PRE map:
      idmap.delete(rpre, id(rpre), -rsize);
      idmap.insert(rpre, meta.lastid - dsize + 1, dsize);
    }

    // update table:
    table.replace(rpre, buffer(), rsize);
    buffer(1);

    // no distance/size update if the two subtrees are of equal size
    if (diff == 0) return;

    // increase/decrease size of ancestors, adjust distances of siblings
    int p = rpar;
    while (p >= 0) {
      final int k = kind(p);
      size(p, k, size(p, k) + diff);
      p = parent(p, k);
    }

    if (!cache) updateDist(rpre + dsize, diff);

    // adjust attribute size of parent if attributes inserted. attribute size
    // of parent cannot be reduced via a replace expression.
    int dpre = clip.start;
    if (data.kind(dpre) == ATTR) {
      int d = 0;
      while (dpre < clip.end && data.kind(dpre++) == ATTR) d++;
      if (d > 1) attSize(rpar, kind(rpar), d + 1);
    }
  }
Exemple #17
0
  /**
   * Inserts a data instance at the specified pre value. Note that the specified data instance must
   * differ from this instance.
   *
   * @param ipre value at which to insert new data
   * @param ipar parent pre value of node
   * @param clip data clip
   */
  public final void insert(final int ipre, final int ipar, final DataClip clip) {
    meta.update();

    // update value and document indexes
    if (meta.updindex) indexBegin();
    resources.insert(ipre, clip);

    final int dsize = clip.size();
    final int buf = Math.min(dsize, IO.BLOCKSIZE >> IO.NODEPOWER);
    // resize buffer to cache more entries
    buffer(buf);

    // find all namespaces in scope to avoid duplicate declarations
    final TokenMap nsScope = nspaces.scope(ipar, this);

    // loop through all entries
    final IntList preStack = new IntList();
    final NSNode nsRoot = nspaces.current();
    final HashSet<NSNode> newNodes = new HashSet<NSNode>();
    final IntList flagPres = new IntList();

    // indicates if database only contains a dummy node
    final Data data = clip.data;
    int c = 0;
    for (int dpre = clip.start; dpre < clip.end; ++dpre, ++c) {
      if (c != 0 && c % buf == 0) insert(ipre + c - buf);

      final int pre = ipre + c;
      final int dkind = data.kind(dpre);
      final int dpar = data.parent(dpre, dkind);
      // ipar < 0 if document nodes on top level are added
      final int dis = dpar >= 0 ? dpre - dpar : ipar >= 0 ? pre - ipar : 0;
      final int par = dis == 0 ? -1 : pre - dis;

      if (c == 0) nspaces.root(par, this);

      while (!preStack.isEmpty() && preStack.peek() > par) nspaces.close(preStack.pop());

      switch (dkind) {
        case DOC:
          // add document
          nspaces.prepare();
          final int s = data.size(dpre, dkind);
          doc(pre, s, data.text(dpre, true));
          meta.ndocs++;
          preStack.push(pre);
          break;
        case ELEM:
          // add element
          nspaces.prepare();
          boolean ne = false;
          if (data.nsFlag(dpre)) {
            final Atts at = data.ns(dpre);
            for (int a = 0; a < at.size(); ++a) {
              // see if prefix has been declared/ is part of current ns scope
              final byte[] old = nsScope.get(at.name(a));
              if (old == null || !eq(old, at.value(a))) {
                // we have to keep track of all new NSNodes that are added
                // to the Namespace structure, as their pre values must not
                // be updated. I.e. if an NSNode N with pre value 3 existed
                // prior to inserting and two new nodes are inserted at
                // location pre == 3 we have to make sure N and only N gets
                // updated.
                newNodes.add(nspaces.add(at.name(a), at.value(a), pre));
                ne = true;
              }
            }
          }
          byte[] nm = data.name(dpre, dkind);
          elem(
              dis,
              tagindex.index(nm, null, false),
              data.attSize(dpre, dkind),
              data.size(dpre, dkind),
              nspaces.uri(nm, true),
              ne);
          preStack.push(pre);
          break;
        case TEXT:
        case COMM:
        case PI:
          // add text
          text(pre, dis, data.text(dpre, true), dkind);
          break;
        case ATTR:
          // add attribute
          nm = data.name(dpre, dkind);
          // check if prefix already in nsScope or not
          final byte[] attPref = prefix(nm);
          // check if prefix of attribute has already been declared, otherwise
          // add declaration to parent node
          if (data.nsFlag(dpre) && nsScope.get(attPref) == null) {
            nspaces.add(
                par,
                preStack.isEmpty() ? -1 : preStack.peek(),
                attPref,
                data.nspaces.uri(data.uri(dpre, dkind)),
                this);
            // save pre value to set ns flag later for this node. can't be done
            // here as direct table access would interfere with the buffer
            flagPres.add(par);
          }
          attr(
              pre,
              dis,
              atnindex.index(nm, null, false),
              data.text(dpre, false),
              nspaces.uri(nm, false),
              false);
          break;
      }
    }
    // finalize and update namespace structure
    while (!preStack.isEmpty()) nspaces.close(preStack.pop());
    nspaces.root(nsRoot);

    if (bp != 0) insert(ipre + c - 1 - (c - 1) % buf);
    // reset buffer to old size
    buffer(1);

    // set ns flags
    for (int f = 0; f < flagPres.size(); f++) {
      final int fl = flagPres.get(f);
      table.write2(fl, 1, name(fl) | 1 << 15);
    }

    // increase size of ancestors
    int p = ipar;
    while (p >= 0) {
      final int k = kind(p);
      size(p, k, size(p, k) + dsize);
      p = parent(p, k);
    }

    if (meta.updindex) {
      // add the entries to the ID -> PRE mapping:
      idmap.insert(ipre, id(ipre), dsize);
      indexEnd();
    }

    if (!cache) updateDist(ipre + dsize, dsize);

    // propagate PRE value shifts to namespaces
    if (ipar != -1) nspaces.insert(ipre, dsize, newNodes);
  }
 /**
  * Returns the pre value of the next child.
  *
  * @return next child reference
  */
 int next() {
   final int p = pre;
   pre += data.size(pre, data.kind(pre));
   return p;
 }