Пример #1
0
  /**
   * Deletes a node and its descendants.
   *
   * @param pre pre value of the node to delete
   */
  public final void delete(final int pre) {
    meta.update();

    // size of the subtree to delete
    int k = kind(pre);
    final int s = size(pre, k);
    resources.delete(pre, s);

    if (meta.updindex) {
      // delete child records from indexes
      indexDelete(pre, s);
    }

    /// explicitly delete text or attribute value
    if (k != DOC && k != ELEM) delete(pre, k != ATTR);

    // reduce size of ancestors
    int par = pre;
    // check if we are an attribute (different size counters)
    if (k == ATTR) {
      par = parent(par, ATTR);
      attSize(par, ELEM, attSize(par, ELEM) - 1);
      size(par, ELEM, size(par, ELEM) - 1);
      k = kind(par);
    }

    // reduce size of ancestors
    while (par > 0 && k != DOC) {
      par = parent(par, k);
      k = kind(par);
      size(par, k, size(par, k) - s);
    }

    // preserve empty root node
    if (kind(pre) == DOC) --meta.ndocs;

    if (meta.updindex) {
      // delete node and descendants from ID -> PRE map:
      idmap.delete(pre, id(pre), -s);
    }

    // delete node from table structure and reduce document size
    table.delete(pre, s);

    if (!cache) updateDist(pre, -s);

    // propagate PRE value shifts to namespaces
    nspaces.delete(pre, s, this);
  }
Пример #2
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;
 }
Пример #3
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;
  }
Пример #4
0
 /**
  * Finds the closest namespace node for the specified pre value.
  *
  * @param pre pre value
  * @param data data reference
  * @return node
  */
 NSNode find(final int pre, final Data data) {
   final int s = find(pre);
   // no match found: return current node
   if (s == -1) return this;
   final NSNode ch = children[s];
   final int cp = ch.pr;
   // return exact hit
   if (cp == pre) return ch;
   // found node is preceding sibling
   if (cp + data.size(cp, Data.ELEM) <= pre) return this;
   // continue recursive search
   return children[s].find(pre, data);
 }
Пример #5
0
  /**
   * Lists resources of the specified database.
   *
   * @return success flag
   * @throws IOException I/O exception
   */
  private boolean listDB() throws IOException {
    final String db = args[0];
    final String path = args[1] != null ? args[1] : "";
    if (!Databases.validName(db)) return error(NAME_INVALID_X, db);

    final Table table = new Table();
    table.description = RESOURCES;
    table.header.add(INPUT_PATH);
    table.header.add(TYPE);
    table.header.add(MimeTypes.CONTENT_TYPE);
    table.header.add(SIZE);

    try {
      // add xml documents
      final Data data = Open.open(db, context);
      final Resources res = data.resources;
      final IntList il = res.docs(path);
      final int ds = il.size();
      for (int i = 0; i < ds; i++) {
        final int pre = il.get(i);
        final TokenList tl = new TokenList(3);
        final byte[] file = data.text(pre, true);
        tl.add(file);
        tl.add(DataText.M_XML);
        tl.add(MimeTypes.APP_XML);
        tl.add(data.size(pre, Data.DOC));
        table.contents.add(tl);
      }
      // add binary resources
      for (final byte[] file : res.binaries(path)) {
        final String f = string(file);
        final TokenList tl = new TokenList(3);
        tl.add(file);
        tl.add(DataText.M_RAW);
        tl.add(MimeTypes.get(f));
        tl.add(data.meta.binary(f).length());
        table.contents.add(tl);
      }
      Close.close(data, context);
    } catch (final IOException ex) {
      return error(Util.message(ex));
    }
    out.println(table.sort().finish());
    return true;
  }
Пример #6
0
  /**
   * 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));
      }
    }
  }
Пример #7
0
  /**
   * 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;
  }
Пример #8
0
  /**
   * 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);
  }
Пример #9
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);
  }
Пример #10
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);
    }
  }
Пример #11
0
 /**
  * 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;
 }
Пример #12
0
 /**
  * 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);
 }
Пример #13
0
 /**
  * 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);
 }
Пример #14
0
 /**
  * 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);
 }