Skip to content
JohannesLichtenberger edited this page Nov 2, 2012 · 15 revisions

Some API examples:

// Create database configuration.`
final DatabaseConfiguration dbConfig = new DatabaseConfiguration(new File(pathToDatabaseDir));

// Create a new lightweight database structure.
Databases.createDatabase(dbConfig);

// Open the database.
try (final Database database = Databases.openDatabase(dbConfig.getFile());) {

  // Create a first resource without text-value compression and without any incremental indexes.
  database.createResource(ResourceConfiguration.builder("shredded", dbConfig).setIndexes(EnumSet.of(Indexes.NONE)).useTextCompression(false).build());

  // Open a new session on the created resource.
  final SessionConfiguration sessionConfig = new SessionConfiguration.Builder("shredded").build();
  try (final Session session = database.getSession(sessionConfig);) {
    // Open only write transaction on the resource (transaction provides a cursor for navigation
    // through moveToX-methods).
    try (final NodeWriteTrx wtx = session.beginNodeWriteTrx();) {
      // Import an XML document.
      wtx.insertSubtree(XMLShredder.createFileReader(pXML), Insert.ASFIRSTCHILD);

      // Commit and persist the changes.
      wtx.commit();

      // Transaction handle can be reused.
      wtx.moveToDocumentRoot();

      // Executes a modification visitor for each descendant node.
      for (final long nodeKey :
        DescendantAxis.builder(wtx).includeSelf().visitor(
          Optional.<Visitor> of(new ModificationVisitor(wtx, wtx.getNodeKey()))).build()) {
        ...
      }

      // Commit second version.
      wtx.commit();

      // Transaction handle is relocated at the document node of the new revision; iterate over "normal" descendant axis.
      final Axis axis = new DescendantAxis(wtx);
      if (axis.hasNext()) {
        axis.next();

        switch (wtx.getKind()) {
        case ELEMENT:
          // Do something.
          break;
        default:
          // Do nothing.
      }
      if (wtx.moveTo(axis.peek()).get().isComment()) {
        LOGGER.info(wtx.getValue());
      }

      // Begin a reading transaction on revision 0 concurrently to the write-transaction on revision 1 (the very first commited revision).
      try (final NodeReadTrx rtx = session.beginNodeReadTrx(0);) {
        // moveToX-methods return true, if the transaction-cursor can be moved, false otherwise.
        rtx.moveToFirstChild();
        rtx.moveToFirstChild();
        rtx.moveToRightSibling();

        // Can be tested before.
        if (rtx.hasRightSibling()) {
          rtx.moveToRightSibling();
        }

        // Move to next node in the XPath following::-axis.
        rtx.moveToNextFollowing();

        // Move to previous node in preorder.
        rtx.moveToPrevious();

        // Move to next node in preorder.
        rtx.moveToNext();

        /* 
         * Or simply within the move-operation and a postcondition check. If hasMoved() returns false, the transaction isn't moved.
         */
        if (rtx.moveToRightSibling().hasMoved()) {
          // Do something.
        }

      // Instead of the following, a visitor is useable!
      switch (rtx.getKind()) {
      case ELEMENT:
        for (int i = 0, nspCount = rtx.getNamespaceCount(); i < nspCount; i++) {
          rtx.moveToNamespace(i);
          LOGGER.info(rtx.getName());
          rtx.moveToParent();
        }

        for (int i = 0, attrCount = rtx.getAttributeCount(); i < attrCount; i++) {
          rtx.moveToAttribute(i);
          LOGGER.info(rtx.getName());
          rtx.moveToParent();
        }

        // Move to the specified attribute by name.
        rtx.moveToAttributeByName(new QName("foobar"));
        rtx.moveToParent();
        
        LOGGER.info(rtx.getDescendantCount());
        LOGGER.info(rtx.getChildCount());
        /* 
         * Hash of a node, build bottom up for all nodes (depends on descendant hashes, however only
         * ancestor nodes are updated during a normal edit-operation. During bulk inserts with 
         * insertSubtree(...) the hashes are generated during a postorder-traversal, just like the 
         * descendant-count of each structural node.
         */
        LOGGER.info(rtx.getHash());
        break;
      case TEXT:
        LOGGER.info(rtx.getValue());
        break;
      case COMMENT:
        LOGGER.info(rtx.getValue());
        break;
      default:
        throw new IllegalStateException("Node kind not known!");
    }
  }

Note that we aim to support all the Guava flavor. Just imagine how nice the following is:

final Iterator<Long> results = FluentIterable.from(new DescendantAxis(rtx)).filter(new ElementFilter(rtx)).limit(2).iterator();

to filter all element nodes and skip after the first 2 elements are found. The resulting iterator contains at most 2 resulting unique node-keys (IDs) to which we can navigate through rtx.moveTo(long).

Furthermore a FilterAxis(Axis, Filter, Filter…) is usable. It’s first parameter is the axis to use, the second parameter is a filter. Optionally further filters are usable (third varargs parameter).

To update a resource with algorithmically found differences between two tree-structures, use something like the following:

// Old Sirix resource to update.
final File resOldRev = new File(args[0]);

// XML document which should be imported as the new revision.
final File resNewRev = new File(args[1]);

// Determine and import differences between the sirix resource and the
// provided XML document.
final FMSEImport fmse = new FMSEImport();
fmse.dataImport(resOldRev, resNewRev);

Method chaining for insertions:

// Setup everything omitted... write transaction opened. Assertion: wtx is located at element node.
wtx.insertAttribute(new QName("foo"), "bar", Move.PARENT).insertElementAsRightSibling(new QName("baz"));

// Copy subtree of the node the read-transaction is located at as a new right sibling.
wtx.copySubtreeAsRightSibling(rtx);

Similarly moveToX()-methods are usable:

// Get returns the transaction cursor currently used. However in this case the caller must be sure that a right sibling of the node denoted by node-key 15 and his right sibling and the right sibling's first child exists.
wtx.moveTo(15).get().moveToRightSibling().get().moveToFirstChild().get().insertCommentAsFirstChild("foo");

A whole bunch of axis is usable (all XPath axis and a few more):

// Simple postorder-axis which iterates in postorder through a (sub)tree.
for (final Axis axis = new PostOrderAxis(rtx); axis.hasNext();) {
  axis.next();
  switch(rtx.getKind()) {
  case TEXT:
    // Do something.
    break;
  }
}

or more elegantly:

// Iterate and use a visitor implementation to describe the behavior for the individual node types.
final Visitor visitor = new MyVisitor(rtx);
for (final Axis axis = new PostOrderAxis(rtx); axis.hasNext();) {
  axis.next();
  rtx.acceptVisitor(visitor);
}

or with the foreach-loop:

// Iterate and use a visitor implementation to describe the behavior for the individual node types.
final Visitor visitor = new MyVisitor(rtx);
for (final long nodeKey : new PostOrderAxis(rtx)) {
  rtx.acceptVisitor(visitor);
}

Furthermore a special filter-axis is provided:

// Filter by name (first argument is the axis, next arguments are filters (which implement org.sirix.axis.filter.IFilter).
for (final Axis axis = new FilterAxis(new VisitorDescendantAxis.Builder(rtx).includeSelf().visitor(Optional.of(visitor)).build(), new NameFilter(rtx, "foobar")); axis.hasNext();) {
  axis.next();
}

Further filters can be specified. All XPath axis are also available, plus a LevelOrderAxis, a ConcurrentAxis which executes the specified axis concurrently. Furthermore a ConcurrentUnionAxis, ConcurrentExceptAxis, ConcurrentIntersectAxis are provided. To allow chained axis, a `NestedAxis` is available which takes two axis as arguments.

The VisitorDescendantAxis above is especially useful as it executes a visitor as one of the first things in the hasNext() iterator-method. The return value of the visitor is used to guide the preorder traversal:

/**
 * The result type of an {@link IVisitor} implementation.
 * 
 * @author Johannes Lichtenberger, University of Konstanz
 */
public enum VisitResult {
  /** Continue without visiting the siblings of this structural node. */
  SKIPSIBLINGS,

  /** Continue without visiting the descendants of this element. */
  SKIPSUBTREE,

  /** Continue traversal. */
  CONTINUE,

  /** Terminate traversal. */
  TERMINATE,
}

Temporal axis to navigate in time will be available in the next few days (for instance to iterate over all future revisions, all past revisions, the last revision, the first revision, a specific revision, the previous revision, the next revision…)

Clone this wiki locally