crossley    2003/02/12 17:43:53

  Modified:    src/documentation/xdocs/howto Tag: cocoon_2_0_3_branch
                        howto-xindice-xmlform.xml
  Log:
  Added patch from Josema Alonso to fix some source line widths.
  Reformatted the whole document to enable proper diff later
  (line-wrap, indent, dos2unix).
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.2   +770 -651  
xml-cocoon2/src/documentation/xdocs/howto/howto-xindice-xmlform.xml
  
  Index: howto-xindice-xmlform.xml
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/documentation/xdocs/howto/howto-xindice-xmlform.xml,v
  retrieving revision 1.1.2.1
  retrieving revision 1.1.2.2
  diff -u -r1.1.2.1 -r1.1.2.2
  --- howto-xindice-xmlform.xml 8 Feb 2003 01:22:27 -0000       1.1.2.1
  +++ howto-xindice-xmlform.xml 13 Feb 2003 01:43:53 -0000      1.1.2.2
  @@ -1,651 +1,770 @@
  -<?xml version="1.0" encoding="utf-8"?>
  -<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" 
"../dtd/document-v10.dtd">
  -<document>
  -     <header>
  -             <title>Xindice within the XMLForm Framework</title>
  -             <authors>
  -                     <person name="Josema Alonso" 
email="[EMAIL PROTECTED]"/>
  -             </authors>
  -     </header>
  -     <body>
  -             <s1 title="Notice">
  -                     <p>This How-To is based on components included in the Cocoon 
2.1
  -      distribution. If you don&#39;t have this version, you can obtain it from
  -      the <link href="../index.html">Apache Cocoon</link> web site.
  -      </p>
  -                     <p> Some user accessible points in the Cocoon 2.1 distribution 
should be
  -      considered &#34;alpha&#34;. This means that the developer team is not
  -      investing _any_ effort to provide backward compatibility between alpha
  -      releases for these parts. This software will continue to be released as
  -      &#34;alpha&#34; until its code, schemas, and APIs are considered stable.
  -      </p>
  -                     <p>Until then, there will be no warranty that newer versions 
will
  -      maintain backward compatibility for such parts, even in the most simple
  -      cases. Of course Cocoon will be compatible to latest release, 2.0.x
  -      release. However, once &#34;beta&#34; status is reached, backward
  -      incompatible changes will be made only when absolutely necessary to
  -      reach &#34;final&#34; status. </p>
  -                     <p>The Cocoon development team understands the importance of 
reliable
  -      software as well protecting user investments through the creation of a
  -      solid development platform that doesn&#39;t change. On the other hand,
  -      the Cocoon project is a pioneer in many fields. Most of the technologies
  -      it uses are at a &#34;working draft&#34; phase only. Thus, reliability
  -      cannot be guaranteed before the software achieves its &#34;final&#34;
  -      status. </p>
  -                     <p>Until then, no effort will be provided to guarantee 
backward
  -      compatibility for any parts considered alpha. </p>
  -                     <p>You have been warned.</p>
  -             </s1>
  -             <s1 title="Overview">
  -                     <p>
  -This How-To shows you how to use Xindice as the repository for XML resources from 
the XMLForm Framework. It requires prior knowledge of Cocoon XMLForm, XSLT, 
Schematron, Xindice and the XMLDB API. 
  -             </p>
  -             </s1>
  -             <s1 title="Purpose">
  -                     <p>
  -You will learn how to build a simple wizard type XMLForm that stores XML data into 
a Xindice collection.
  -</p>
  -             </s1>
  -             <s1 title="Intended Audience">
  -                     <p>
  -Cocoon users who want to learn how to store data obtained from XMLForms into 
Xindice.
  -</p>
  -             </s1>
  -             <s1 title="Prerequisites">
  -                     <p>Cocoon must be running on your system. The steps below have 
been tested with Cocoon 2.1-dev.</p>
  -                     <p>You will need the following:</p>
  -                     <ul>
  -                             <li>A servlet engine such as Tomcat.</li>
  -                             <li>JDK 1.2 or later</li>
  -                             <li>Xindice 1.0 installed (create a collection named 
<code>Artist</code>)</li>
  -                     </ul>
  -                     <p>Cocoon 2.1 CVS to be installed with the command:</p>
  -                     <source>build -Dinclude.webapp.libs=true webapp</source>
  -                     <p>
  -You will need to understand and be familiar with XSL, XForms, XPath, Schematron and 
Xindice. Some knowledge about JXPath and the XMLDB API would be helpful, too. If you 
are unfamiliar with these technologies, it is advised that you learn these related 
concepts first. If you are unfamiliar with XMLForm, check out the <link 
href="xmlform-wizard/howto-xmlform-wizard.html">XMLForm Wizard How-To</link> first.
  -                     </p>
  -             </s1>
  -             <s1 title="Steps">
  -                     <p>
  -We will follow the needed steps in order to add a document like the one below to a 
Xindice collection named <code>Artist</code>.
  -                     </p>
  -                     <source><![CDATA[
  -<Artist id="pearljam">
  -    <Name>Pearl Jam</Name>
  -</Artist>]]></source>
  -                     <p>
  -We will get the identifier and name data using a XMLForm and store them in Xindice. 
We will build this XMLForm very similar to the one in the XMLForm Wizard How-To. 
  -                     </p>
  -                     <s2 title="1. Building the XMLForm files">
  -                             <p>
  -Create the files and name them as specified below. 
  -                             </p>
  -                             <s3 title="start.xform">
  -                             <source><![CDATA[
  -<?xml version="1.0"?>
  -<document>
  -  <h1>This is the New Artist Wizard!</h1>
  -  <info>Steps from here on, will let you insert a new
  -        Artist in the database.
  -  </info>
  -  <h3>
  -    <a href="Artist.xform?cocoon-action-start=true">
  -       Start!
  -    </a>
  -  </h3>
  -</document>]]>
  -                             </source>
  -                             </s3>
  -                             <p></p>
  -                             <s3 title="artist.xform">
  -                             <source><![CDATA[
  -<?xml version="1.0"?>
  -<document xmlns:xf="http://xml.apache.org/cocoon/xmlform/2002";>
  -  <xf:form id="artist-insert" view="artist" action="Artist.xform" method="post">
  -    <xf:caption>New Artist</xf:caption>
  -    <error>
  -      <xf:violations class="error"/>
  -    </error>
  -    <xf:textbox ref="/Artist/@id">
  -      <xf:caption>Artist identifier:</xf:caption>
  -    </xf:textbox>
  -    <xf:textbox ref="/Artist/Name">
  -      <xf:caption>Artist Name:</xf:caption>
  -    </xf:textbox>
  -    <xf:submit id="prev" class="button">
  -      <xf:caption>Prev</xf:caption>
  -      <xf:hint>Go to previous page</xf:hint>
  -    </xf:submit>
  -    <xf:submit id="next" class="button">
  -      <xf:caption>Next</xf:caption>
  -      <xf:hint>Go to next page</xf:hint>
  -    </xf:submit>
  -  </xf:form>
  -</document>]]>                               </source>
  -                             </s3>
  -                             <p></p>
  -                             <s3 title="end.xform">
  -                             <source><![CDATA[
  -<?xml version="1.0"?>
  -<document>
  -  <h1>You have reached the last page!</h1>
  -  <info>
  -   You have inserted a New Artist successfully.
  -  </info>
  -  <h3>
  -    <a href="Artist.xform">Go to home page.</a>
  -  </h3>
  -</document>]]></source>
  -                             </s3>
  -                             <p></p>
  -                             <s3 title="error.xform">
  -                             <source><![CDATA[
  -<?xml version="1.0"?>
  -<document>
  -  <h1>
  -    You have reached the last page of the New Artist Wizard!
  -  </h1>
  -  <info>
  -    There have been problems and the Artist could not be added to the database.
  -    Please try again.
  -  </info>
  -  <h3>
  -    <a href="Artist.xform">Please, start again.</a>
  -  </h3>
  -</document>]]></source>
  -                             </s3>
  -                             <p></p>
  -                     </s2>
  -                     <s2 title="2. Validation">
  -                             <p>
  -For the sake of simplicity we just validate one property against one condition. We 
require the identifier to be at least two characters in length; the validation file, 
<strong><code>artist-validator.xml</code></strong> is as follows:</p>
  -                             <source><![CDATA[
  -<?xml version="1.0"?>
  -<schema ns="http://xml.apache.cocoon/xmlform"; 
xmlns="http://www.ascc.net/xml/schematron";>
  -  <phase id="artist">
  -    <active pattern="artval"/>
  -  </phase>
  -  <pattern name="Artist Identifier Validation" id="artval">
  -    <rule context="/Artist/@id">
  -      <assert test="string-length(.) > 1">
  -        Artist Name should be at least 2 characters.
  -      </assert>
  -    </rule>
  -  </pattern>
  -</schema>]]></source>
  -                     <p></p>
  -                     <s3 title="Extended Validation">
  -                     <p>
  -There could be more complicated rules in Schematron but we could also require the 
identifier to be unique in the database. In this case we should query the database and 
see if it already exists. If so, a new violation can be added to the form. Since these 
kinds of violations are out of the scope of Schematron, these operations should be 
accomplished in the Action using Java code. 
  -                     </p>
  -                     </s3>
  -                     <p></p>
  -                     </s2>
  -                     <s2 title="3. The Model">
  -                             <p>
  -Here is where we will take a different approach to the one in the XMLForm Wizard 
How-To. We will not use a separate Bean. In order to have an XML document model we 
will create an XML file with the empty structure we want to fill with data from the 
form. Create the file <strong><code>artist-model.xml</code></strong> and fill it with:
  -                             </p>
  -                             <source><![CDATA[
  -<Artist id="">
  -    <Name></Name>
  -</Artist>]]></source>
  -                     <p>
  -Persistence for the data will be accomplished by using a <link 
href="http://jakarta.apache.org/commons/jxpath/apidocs/org/apache/commons/jxpath/Container.html";>JXPath
 Container</link>. The XML document model created above will be loaded into the 
Container. We will use the <code>xmlform-model</code> parameter in the sitemap to 
point to the XML file.
  -The Container is created and manipulated by the Action in its 
<code>getFormModel()</code> method, so we need to override it and write it this way 
(we'll see the whole Action in the next step): 
  -                     </p>
  -                     <source><![CDATA[
  -/**
  - * Extract xmlform-model parameter and
  - * instantiate a new form model from it.
  - */
  -  protected Object getFormModel() { 
  -    //to load the XML model
  -    Container DOMModel = null;
  -    Source modelSrc = null;
  -    //this parameter holds the name of the empty XML document representing the 
model
  -    String modelFileName = getParameters().getParameter("xmlform-model", null);
  -    if(modelFileName==null) return null;
  -    try {
  -        modelSrc = getSourceResolver().resolveURI(modelFileName);
  -        DOMModel = new XMLDocumentContainer(new 
StreamSource(modelSrc.getInputStream()));
  -        return DOMModel;
  -      }
  -      catch ( Exception e) {
  -        throw new CascadingRuntimeException( " Failed instantiating form model ", e 
);
  -      }
  -      finally {
  -        getSourceResolver().release(modelSrc);
  -      }
  -  }]]></source>
  -                     <p></p>
  -                     </s2>
  -                     <s2 title="4. The Action">
  -                             <p>
  -In this Action we have integrated the Xindice handling code, getting the data from 
the model and storing it in Xindice. The Action that controls this form is 
<strong><code>ArtistAction.java</code></strong>:</p>
  -                             <source><![CDATA[
  -package com.simbiosystems.cocoon.xmlform.xindice.howto;
  -
  -import java.util.Arrays;
  -import java.util.Map;
  -
  -import javax.xml.transform.stream.StreamSource;
  -import org.apache.avalon.framework.CascadingRuntimeException;
  -import org.apache.cocoon.acting.AbstractXMLFormAction;
  -import org.apache.cocoon.components.validation.Violation;
  -import org.apache.cocoon.components.xmlform.Form;
  -import org.apache.cocoon.components.xmlform.FormListener;
  -import org.apache.commons.jxpath.Container;
  -import org.apache.commons.jxpath.XMLDocumentContainer;
  -import org.apache.excalibur.source.Source;
  -import org.w3c.dom.Document;
  -import org.w3c.dom.Node;
  -
  -/**
  - * This action handles XMLForms for the Artist data
  - */
  -public class ArtistAction extends AbstractXMLFormAction implements FormListener {
  -  // different form views participating in the form
  -  final String VIEW_START = "start";
  -  final String VIEW_ARTIST = "artist";
  -  final String VIEW_END = "end";
  -  final String VIEW_ERROR = "error";
  -  // action commands used in the wizard
  -  final String CMD_START = "start";
  -  final String CMD_NEXT = "next";
  -  final String CMD_PREV = "prev";
  -  //constant for the XML manipulation, it holds the full name of the collection
  -  //to be used for storing the data
  -  final String xindiceSubCol = "/Artist";
  -
  -  /**
  -   * Extract xmlform-model action parameter and
  -   * instantiate a new form model from it.
  -   *
  -   * In this case it uses a JXPath Container as the model and
  -   * there is no need for a separate model Bean.
  -   *
  -   * @return Form the form object this action works with.
  -   *
  -   */
  -  protected Object getFormModel() {
  -    //to load the XML model
  -    Container DOMModel = null;
  -    Source modelSrc = null;
  -    //this parameter holds the name of the empty XML document representing the 
model
  -    String modelFileName = getParameters().getParameter("xmlform-model", null);
  -    if(modelFileName==null) return null;
  -    try {
  -      modelSrc = getSourceResolver().resolveURI(modelFileName);
  -      DOMModel = new XMLDocumentContainer(new 
StreamSource(modelSrc.getInputStream()));
  -      return DOMModel;
  -    }
  -    catch ( Exception e) {
  -      throw new CascadingRuntimeException( " Failed instantiating form model ", e 
);
  -    }
  -    finally {
  -      getSourceResolver().release(modelSrc);
  -    }
  -  }
  -
  -  /**
  -   * Invoked after form population
  -   * Take appropriate action based on the command
  -   *
  -   */
  -  public Map perform () {
  -    // set the page control flow parameter
  -    // according to the validation result
  -    if ( getCommand().equals(CMD_NEXT) && getForm().getViolations () != null ) {
  -      // errors, back to the same page
  -      return page( getFormView() );
  -    }
  -    else {
  -      // validation passed
  -      // continue with control flow
  -      // clear validation left overs in case the user
  -      // did not press the Next button
  -      getForm().clearViolations();
  -      // get the user submitted command
  -      String command = getCommand();
  -      // get the form view which was submitted
  -      String formView = getFormView();
  -      // apply control flow rules
  -      if (formView.equals (VIEW_ARTIST)) {
  -        if (command.equals(CMD_NEXT)) {
  -          //extended validation
  -          //test if the ID already exists in the DB
  -          String artistName = (String)getForm().getValue("/Artist/@id");
  -          try {
  -            XindiceManager xi = new XindiceManager();
  -            Node result = xi.find(xindiceSubCol, "/Artist[@id='"+ artistName +"']", 
"Artist");
  -           //if we do not get null the element with that ID
  -           //already existed and we add the violation
  -            if (result!=null) {
  -              Violation v = new Violation();
  -              v.setMessage("already exists in the database, please choose another 
one");
  -              v.setPath("/Artist/@id");
  -              Violation[] va = { v };
  -              getForm().addViolations(Arrays.asList((Object[])va));
  -             //the ID already exists, back to the same
  -             //page to correct the error
  -              return page(VIEW_ARTIST);
  -            }
  -          }
  -          catch (Exception e) {
  -            getLogger().error("Cannot establish a connection to the DB", e);
  -          }
  -          //everything went fine, add the document to the database
  -          try {
  -             addDocument();
  -          }
  -          catch(Exception e) {
  -            //there were errors, send it to the error page
  -            getLogger().error("Cannot add DOM document to the database");
  -            return page(VIEW_ERROR);
  -          }
  -          return page( VIEW_END);
  -
  -       }
  -        if (command.equals(CMD_PREV)) {
  -          return page(VIEW_START);
  -        }
  -      }
  -    }
  -    // should never reach this statement
  -    return page( VIEW_START );
  -  }
  -
  -  /**
  -   * The first callback method which is called
  -   * when an action is invoked.
  -   *
  -   * It is called before population.
  -   * @return null if the Action is ready to continue.
  -   * an objectModel map which will be returned
  -   */
  -  protected Map prepare() {
  -    if ( getCommand() == null ) {
  -      return page(VIEW_START);
  -    }
  -    else if ( getCommand().equals(CMD_START)) {
  -      // reset state by removing old form if one exists
  -      Form.remove( getObjectModel(), getFormId() );
  -      getForm().addFormListener( this );
  -      return page(VIEW_ARTIST);
  -    }
  -    // get ready for action
  -    // if not ready return page("whereNext");
  -    return null;
  -  }
  -
  -  /**
  -   * Add the document to the database
  -   *
  -   */
  -  public void addDocument() throws Exception {
  -    try {
  -      //add the document to the database
  -      XindiceManager xi = new XindiceManager();
  -      //needs the DocumentRoot of the Container as a DOM Node
  -      xi.add(xindiceSubCol, 
  -             
((Document)(((XMLDocumentContainer)(getForm().getModel())).getValue())).getDocumentElement(),
 
  -             null);
  -    }
  -    catch (Exception e) {
  -      getLogger().error("DOM Document could not be created", e);
  -      throw e;
  -    }
  -  }
  -}]]></source>
  -                             <p>
  -We had to use an ugly casting mechanism in the <code>addDocument</code> method but 
that's what we have by now. In future JXPath versions this will be easier to 
accomplish. 
  -                             </p>
  -                     <s3 title="The helper class">
  -                             <p>
  -In order to make this work we need to use a helper class. This class uses the XMLDB 
API to connect to Xindice and make the operations available to the Action. You should 
extend it to add more operations. The helper class 
<strong><code>XindiceManager.java</code></strong> is as follows: 
  -                             </p>
  -                     <source><![CDATA[
  -/**
  - * Helper class for Xindice related operations
  - *
  - */
  -package com.simbiosystems.cocoon.xmlform.xindice.howto;
  -
  -import javax.xml.parsers.DocumentBuilder;
  -import javax.xml.parsers.DocumentBuilderFactory;
  -import org.w3c.dom.DOMImplementation;
  -import org.w3c.dom.Document;
  -import org.w3c.dom.Element;
  -import org.w3c.dom.Node;
  -import org.xmldb.api.DatabaseManager;
  -import org.xmldb.api.base.Collection;
  -import org.xmldb.api.base.Database;
  -import org.xmldb.api.base.Resource;
  -import org.xmldb.api.base.ResourceIterator;
  -import org.xmldb.api.base.ResourceSet;
  -import org.xmldb.api.base.XMLDBException;
  -import org.xmldb.api.modules.XMLResource;
  -import org.xmldb.api.modules.XPathQueryService;
  -
  -public class XindiceManager {
  -
  -  private static final String driver = 
"org.apache.xindice.client.xmldb.DatabaseImpl";
  -  private static final String rootCollection = "xmldb:xindice:///db/";
  -
  -  /**
  -   * Constructor
  -   *
  -   */
  -  public XindiceManager() {
  -
  -  }
  -
  -  /**
  -   * Search for a document in the DB. If not found, return null.
  -   *
  -   * @param subCol name of the subCollection to query if any. If blank or null,
  -   * queries go against the rootCollection.
  -   * @param xpath XPath expression for the query, if none, it returns the whole 
Collection
  -   * @param resultRootelement name of the root element for the DOM document which 
will 
  -   * wrap the results
  -   * @return a DOM Node with the matched documents
  -   *
  -   */
  -  public Node find(String subCol, String xpath, String resultRootElement)
  -    throws Exception {
  -
  -    //prepare DOM document
  -    DOMImplementation impl;
  -    DocumentBuilder builder;
  -    try {
  -      // Find the implementation
  -      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  -      factory.setNamespaceAware( false );
  -      factory.setValidating ( false );
  -      builder = factory.newDocumentBuilder();
  -      impl = builder.getDOMImplementation();
  -    }
  -    catch (Exception ex) {
  -      throw new RuntimeException("[XindiceManager.find]: Failed to initialize DOM 
factory.
  -                                  Root cause: \n" + ex);
  -    }
  -    //create the Document which will hold the results
  -    Document resultDoc = impl.createDocument(null, resultRootElement, null);
  -    Node root = resultDoc.getDocumentElement();
  -
  -    //And now the Xindice part
  -    Collection col = null;
  -    String strData = null;
  -
  -    try {
  -      Class c = Class.forName(driver);
  -
  -      Database database = (Database) c.newInstance();
  -      DatabaseManager.registerDatabase(database);
  -
  -      String localCol = rootCollection + subCol;
  -
  -      col = DatabaseManager.getCollection(localCol);
  -
  -      //Make the XPath query and get the resources
  -      XPathQueryService service =
  -        (XPathQueryService) col.getService("XPathQueryService", "1.0");
  -      ResourceSet resultSet = service.query(xpath);
  -      // Iterate the xpath results and add each of them to the main Document
  -      ResourceIterator iterator = resultSet.getIterator();
  -
  -      //if not resources are present, just return null
  -      if(!iterator.hasMoreResources()) return null;
  -
  -      while(iterator.hasMoreResources()) {
  -        Resource r = iterator.nextResource();
  -
  -        Element resElement = 
((Document)((XMLResource)r).getContentAsDOM()).getDocumentElement();
  -
  -        // Remove unwanted attributes
  -        resElement.removeAttribute("src:col");
  -        resElement.removeAttribute("src:key");
  -        resElement.removeAttribute("xmlns:src");
  -
  -        // Add this result to the root element
  -        Element importedElement = (Element)resultDoc.importNode(resElement, true);
  -        root.appendChild(importedElement);
  -      }
  -      //return the Document root
  -      return root;
  -    }
  -    catch (Exception e) {
  -      System.err.println("[XindiceManager.find]: Find Exception occured :" + 
e.getMessage());
  -      throw e;
  -    }
  -    finally {
  -      if (col != null) {
  -        col.close();
  -      }
  -    }
  -  }
  -
  -  /**
  -   * Add a document to the DB. If a key is not passed, it generates a unique one.
  -   * This version uses a DOM Document.
  -   * @param subCol name of the subCollection in which to add the resource if any. 
If blank or 
  -   * null, insertions go against the rootCollection.
  -   * @param document DOM document to be inserted
  -   * @param key unique key for the resource to be created, if none, one is created 
on the fly
  -   */
  -  public void add(String subCol, Node document, String key) throws Exception {
  -    Collection col = null;
  -    Node xmldoc = null;
  -    try {
  -      Class c = Class.forName(driver);
  -
  -      Database database = (Database) c.newInstance();
  -      DatabaseManager.registerDatabase(database);
  -
  -      col = DatabaseManager.getCollection(rootCollection + subCol);
  -
  -      XMLResource document_ = (XMLResource) col.createResource(null, 
"XMLResource");
  -      document_.setContentAsDOM(document);
  -      col.storeResource(document_);
  -    }
  -    catch (XMLDBException e) {
  -      System.err.println("("[XindiceManager.add]: Add Exception occured " + 
e.errorCode);
  -      throw e;
  -    }
  -    finally {
  -      if (col != null) {
  -        col.close();
  -      }
  -    }
  -  }
  -}]]></source>
  -                     <p></p>
  -                     </s3>
  -                     </s2>
  -                     <s2 title="5. The Sitemap">
  -                             <p>
  -Remember you should have the <code>XMLFormTransformer</code> defined like this:
  -                             </p>
  -                             <source><![CDATA[
  -<map:transformer name="xmlform"
  -                 src="org.apache.cocoon.transformation.XMLFormTransformer" 
  -                 logger="xmlform"/>]]></source>
  -                             <p>
  -Then, you must declare the Action to be used in the correspondent section: 
  -                             </p>
  -                             <source><![CDATA[
  -<map:action logger="xmlform" 
  -            name="ArtistAction"
  -            
src="com.simbiosystems.cocoon.xmlform.xindice.howto.ArtistAction"/>]]></source>
  -                     <p></p>
  -                     <s3 title="The Pipeline">
  -                     <p>
  -                     The following pipeline will process requests to our Form:
  -                     </p>
  -                             <source><![CDATA[
  -<!-- XMLForms<->Xindice pipeline -->
  -<map:pipeline>
  -  <map:match pattern="Artist.xform">
  -    <map:act type="ArtistAction">
  -      <!-- XMLForm parameters for the Action -->
  -      <!-- Notice how we use an XML file as the model -->
  -      <map:parameter name="xmlform-validator-schema-ns" 
value="http://www.ascc.net/xml/schematron"/>
  -      <map:parameter name="xmlform-validator-schema" 
value="artist/artist-validator.xml"/>
  -      <map:parameter name="xmlform-id" value="artist-insert"/>
  -      <map:parameter name="xmlform-scope" value="session"/>
  -      <map:parameter name="xmlform-model" value="artist/artist-model.xml"/>
  -      <!-- XMLForm document, {page} comes from Action -->
  -      <map:generate src="artist/{page}.xform"/>
  -    </map:act>
  -    <!-- populating the doc with model instance data -->
  -    <map:transform type="xmlform"/>
  -    <!-- look and feel of the form controls  -->
  -    <map:transform src="styles/wizard2html.xsl"/>
  -    <!-- Transforming the XMLForm controls to HTML -->
  -    <map:transform src="styles/xmlform2html.xsl"/>
  -    <!-- sending the HTML back to the browser -->
  -    <map:serialize type="html"/>
  -  </map:match>
  -</map:pipeline>]]></source>
  -                     <p>
  -Depending on where you have Cocoon installed and where you have configured the 
files in this how-to, you could make a request to a URL like 
<code>http://localhost:8080/cocoon/Artist.xform</code> and start using the Form. 
  -                     </p>
  -                     </s3>
  -                     </s2>
  -             </s1>
  -             <s1 title="Final Considerations">
  -             <p>
  -Making the operations from the Action using the helper class seems to be the 
easiest way. You can think of other ways or other operations using other Xindice tools 
available in Cocoon such as the pseudo protocol. For example, you could use it to 
query the DB for data that could be stored in a sitemap parameter. You could then get 
the data from the Action and use it to fill a selectbox in the form.
  -             </p>
  -             <p>
  -We did not mentioned other operations such as updates. This can be also 
accomplished this way. For example, if you want to edit the data we just stored, you 
could load it in the Container at the beginning by using the find method of the helper 
class. This way you get a filled form in the next step ready for editing. Other ways 
or interacting with the repository include the XMLDB Transformer. Since it uses 
XUpdate alike syntax, you could format a XML String for it in the last step of the 
Action, making it available to the sitemap then, so the Transformer could get it and 
make the operations.
  -             </p>
  -             <p>
  -I'm sure you can think of more different ways. I encourage you to contribute them 
if you have tested it successfully.
  -This how-to was refactored quite a bit from a original version which used a regular 
Javabean as a wrapper for a DOM Node where the data were persisted. This new version 
version is much more elegant and short. If you want to check differences, an <link 
href="http://wiki.cocoondev.org/Wiki.jsp?page=XMLFormXindiceOldVersion";>old version at 
Cocoon Wiki</link> still exists.
  -             </p>
  -             </s1>
  -             <s1 title="Summary">
  -                     <p>
  -This How-To makes possible the use of Xindice from XMLForms in order to add data to 
the repository. You learned how to connect to the DB from the Action, and how to make 
complex validation using information stored in the DB. Remember that everything you 
have just built is reusable for different user agents. You would only need to use 
<link href="../userdocs/concepts/matchers_selectors.html">matchers and 
selectors</link> and to choose the appropriate transformation. I hope this how-to was 
helpful for you.
  -</p>
  -             </s1>
  -             <s1 title="References">
  -                     <anchor id="references"/>
  -                     <p>
  -This how-to would not be possible without some ideas exchanged with Ivelin Ivanov 
in the <link href="../mail-lists.html">Cocoon Users</link> list and privately.</p>
  -             </s1>
  -             <s1 title="Comments">
  -                     <p>
  -Care to comment on this How-To? Got another tip? 
  -Help keep this How-To relevant by passing along any useful feedback to the author,
  -<link href="mailto:josema|at|simbiosystems.com">Josema Alonso</link>.
  -</p>
  -             </s1>
  -             <s1 title="Revisions">
  -                     <p>
  -02-04-03: First version contributed by Josema Alonso. 
  -  </p>
  -             </s1>
  -     </body>
  -</document>
  +<?xml version="1.0" encoding="utf-8"?>
  +<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" 
"../dtd/document-v10.dtd">
  +<document>
  +  <header>
  +    <title>Xindice within the XMLForm Framework</title>
  +    <authors>
  +      <person name="Josema Alonso" email="[EMAIL PROTECTED]"/>
  +    </authors>
  +  </header>
  +  <body>
  +    <s1 title="Notice">
  +      <p>This How-To is based on components included in the Cocoon 2.1
  +      distribution. If you do not have this version, you can obtain it from
  +      the <link href="../index.html">Apache Cocoon</link> web site.
  +      </p>
  +      <p> Some user accessible points in the Cocoon 2.1 distribution should be
  +      considered &#34;alpha&#34;. This means that the developer team is not
  +      investing _any_ effort to provide backward compatibility between alpha
  +      releases for these parts. This software will continue to be released as
  +      &#34;alpha&#34; until its code, schemas, and APIs are considered stable.
  +      </p>
  +      <p>Until then, there will be no warranty that newer versions will
  +      maintain backward compatibility for such parts, even in the most simple
  +      cases. Of course Cocoon will be compatible to latest release, 2.0.x
  +      release. However, once &#34;beta&#34; status is reached, backward
  +      incompatible changes will be made only when absolutely necessary to
  +      reach &#34;final&#34; status. </p>
  +      <p>The Cocoon development team understands the importance of reliable
  +      software as well protecting user investments through the creation of a
  +      solid development platform that does not change. On the other hand,
  +      the Cocoon project is a pioneer in many fields. Most of the technologies
  +      it uses are at a &#34;working draft&#34; phase only. Thus, reliability
  +      cannot be guaranteed before the software achieves its &#34;final&#34;
  +      status. </p>
  +      <p>Until then, no effort will be provided to guarantee backward
  +      compatibility for any parts considered alpha. </p>
  +      <p>You have been warned.</p>
  +    </s1>
  +    <s1 title="Overview">
  +      <p>
  +        This How-To shows you how to use Xindice as the repository for
  +        XML resources from the XMLForm Framework. It requires prior
  +        knowledge of Cocoon XMLForm, XSLT, Schematron, Xindice and the
  +        XMLDB API. 
  +    </p>
  +    </s1>
  +    <s1 title="Purpose">
  +      <p>
  +        You will learn how to build a simple wizard type XMLForm that
  +        stores XML data into a Xindice collection.
  +      </p>
  +    </s1>
  +    <s1 title="Intended Audience">
  +      <p>
  +        Cocoon users who want to learn how to store data obtained from
  +        XMLForms into Xindice.
  +      </p>
  +    </s1>
  +    <s1 title="Prerequisites">
  +      <p>Cocoon must be running on your system. The steps below have been
  +        tested with Cocoon 2.1-dev.</p>
  +      <p>You will need the following:</p>
  +      <ul>
  +        <li>A servlet engine such as Tomcat.</li>
  +        <li>JDK 1.2 or later</li>
  +        <li>Xindice 1.0 installed (create a collection named
  +          <code>Artist</code>)</li>
  +      </ul>
  +      <p>Cocoon 2.1 CVS to be installed with the command:</p>
  +      <source>build -Dinclude.webapp.libs=true webapp</source>
  +      <p>
  +        You will need to understand and be familiar with XSL, XForms,
  +        XPath, Schematron and Xindice. Some knowledge about JXPath and the
  +        XMLDB API would be helpful, too. If you are unfamiliar with these
  +        technologies, it is advised that you learn these related concepts
  +        first. If you are unfamiliar with XMLForm, check out the
  +        <link href="xmlform-wizard/howto-xmlform-wizard.html">XMLForm
  +        Wizard How-To</link> first.
  +      </p>
  +    </s1>
  +    <s1 title="Steps">
  +      <p>
  +        We will follow the needed steps in order to add a document like
  +        the one below to a Xindice collection named <code>Artist</code>.
  +      </p>
  +      <source><![CDATA[
  +<Artist id="pearljam">
  +    <Name>Pearl Jam</Name>
  +</Artist>]]></source>
  +      <p>
  +        We will get the identifier and name data using a XMLForm and
  +        store them in Xindice. We will build this XMLForm very similar to
  +        the one in the XMLForm Wizard How-To. 
  +      </p>
  +      <s2 title="1. Building the XMLForm files">
  +        <p>
  +          Create the files and name them as specified below. 
  +        </p>
  +        <s3 title="start.xform">
  +          <source><![CDATA[
  +<?xml version="1.0"?>
  +<document>
  +  <h1>This is the New Artist Wizard!</h1>
  +  <info>Steps from here on, will let you insert a new
  +        Artist in the database.
  +  </info>
  +  <h3>
  +    <a href="Artist.xform?cocoon-action-start=true">
  +       Start!
  +    </a>
  +  </h3>
  +</document>]]></source>
  +        </s3>
  +        <p/>
  +        <s3 title="artist.xform">
  +          <source><![CDATA[
  +<?xml version="1.0"?>
  +<document xmlns:xf="http://xml.apache.org/cocoon/xmlform/2002";>
  +  <xf:form id="artist-insert" view="artist"
  +           action="Artist.xform" method="post">
  +    <xf:caption>New Artist</xf:caption>
  +    <error>
  +      <xf:violations class="error"/>
  +    </error>
  +    <xf:textbox ref="/Artist/@id">
  +      <xf:caption>Artist identifier:</xf:caption>
  +    </xf:textbox>
  +    <xf:textbox ref="/Artist/Name">
  +      <xf:caption>Artist Name:</xf:caption>
  +    </xf:textbox>
  +    <xf:submit id="prev" class="button">
  +      <xf:caption>Prev</xf:caption>
  +      <xf:hint>Go to previous page</xf:hint>
  +    </xf:submit>
  +    <xf:submit id="next" class="button">
  +      <xf:caption>Next</xf:caption>
  +      <xf:hint>Go to next page</xf:hint>
  +    </xf:submit>
  +  </xf:form>
  +</document>]]></source>
  +        </s3>
  +        <p/>
  +        <s3 title="end.xform">
  +          <source><![CDATA[
  +<?xml version="1.0"?>
  +<document>
  +  <h1>You have reached the last page!</h1>
  +  <info>
  +   You have inserted a New Artist successfully.
  +  </info>
  +  <h3>
  +    <a href="Artist.xform">Go to home page.</a>
  +  </h3>
  +</document>]]></source>
  +        </s3>
  +        <p/>
  +        <s3 title="error.xform">
  +          <source><![CDATA[
  +<?xml version="1.0"?>
  +<document>
  +  <h1>
  +    You have reached the last page of the New Artist Wizard!
  +  </h1>
  +  <info>
  +    There have been problems and the Artist could not be added to the
  +    database. Please try again.
  +  </info>
  +  <h3>
  +    <a href="Artist.xform">Please, start again.</a>
  +  </h3>
  +</document>]]></source>
  +        </s3>
  +        <p/>
  +      </s2>
  +      <s2 title="2. Validation">
  +        <p>
  +          For the sake of simplicity we just validate one property against
  +          one condition. We require the identifier to be at least two
  +          characters in length; the validation file,
  +          <strong><code>artist-validator.xml</code></strong> is as follows:
  +        </p>
  +        <source><![CDATA[
  +<?xml version="1.0"?>
  +<schema ns="http://xml.apache.cocoon/xmlform"; 
  +        xmlns="http://www.ascc.net/xml/schematron";>
  +  <phase id="artist">
  +    <active pattern="artval"/>
  +  </phase>
  +  <pattern name="Artist Identifier Validation" id="artval">
  +    <rule context="/Artist/@id">
  +      <assert test="string-length(.) > 1">
  +        Artist Name should be at least 2 characters.
  +      </assert>
  +    </rule>
  +  </pattern>
  +</schema>]]></source>
  +        <p/>
  +        <s3 title="Extended Validation">
  +          <p>
  +            There could be more complicated rules in Schematron but we
  +            could also require the identifier to be unique in the
  +            database. In this case we should query the database and see
  +            if it already exists. If so, a new violation can be added to
  +            the form. Since these kinds of violations are out of the scope
  +            of Schematron, these operations should be accomplished in the
  +            Action using Java code. 
  +          </p>
  +        </s3>
  +        <p/>
  +      </s2>
  +      <s2 title="3. The Model">
  +        <p>
  +          Here is where we will take a different approach to the one in
  +          the XMLForm Wizard How-To. We will not use a separate Bean.
  +          In order to have an XML document model we will create an XML
  +          file with the empty structure we want to fill with data from
  +          the form. Create the file
  +          <strong><code>artist-model.xml</code></strong> and fill it with:
  +        </p>
  +        <source><![CDATA[
  +<Artist id="">
  +    <Name></Name>
  +</Artist>]]></source>
  +        <p>
  +          Persistence for the data will be accomplished by using a
  +          <link 
href="http://jakarta.apache.org/commons/jxpath/apidocs/org/apache/commons/jxpath/Container.html";>JXPath
 Container</link>.
  +          The XML document model created above will be loaded into the
  +          Container. We will use the <code>xmlform-model</code> parameter
  +          in the sitemap to point to the XML file.
  +          The Container is created and manipulated by the Action in its
  +          <code>getFormModel()</code> method, so we need to override it
  +          and write it this way (we will see the whole Action in the next
  +          step): 
  +      </p>
  +        <source><![CDATA[
  +/**
  + * Extract xmlform-model parameter and
  + * instantiate a new form model from it.
  + */
  +  protected Object getFormModel() { 
  +    //to load the XML model
  +    Container DOMModel = null;
  +    Source modelSrc = null;
  +    //this parameter holds the name of the empty XML document
  +    //representing the model
  +    String modelFileName =
  +        getParameters().getParameter("xmlform-model", null);
  +    if(modelFileName==null) return null;
  +    try {
  +        modelSrc = getSourceResolver().resolveURI(modelFileName);
  +        DOMModel = new XMLDocumentContainer(new
  +            StreamSource(modelSrc.getInputStream()));
  +        return DOMModel;
  +      }
  +      catch ( Exception e) {
  +        throw new CascadingRuntimeException(
  +            " Failed instantiating form model ", e );
  +      }
  +      finally {
  +        getSourceResolver().release(modelSrc);
  +      }
  +  }]]></source>
  +        <p/>
  +      </s2>
  +      <s2 title="4. The Action">
  +        <p>
  +          In this Action we have integrated the Xindice handling code,
  +          getting the data from the model and storing it in Xindice.
  +          The Action that controls this form is
  +          <strong><code>ArtistAction.java</code></strong>:
  +        </p>
  +        <source><![CDATA[
  +package com.simbiosystems.cocoon.xmlform.xindice.howto;
  +
  +import java.util.Arrays;
  +import java.util.Map;
  +
  +import javax.xml.transform.stream.StreamSource;
  +import org.apache.avalon.framework.CascadingRuntimeException;
  +import org.apache.cocoon.acting.AbstractXMLFormAction;
  +import org.apache.cocoon.components.validation.Violation;
  +import org.apache.cocoon.components.xmlform.Form;
  +import org.apache.cocoon.components.xmlform.FormListener;
  +import org.apache.commons.jxpath.Container;
  +import org.apache.commons.jxpath.XMLDocumentContainer;
  +import org.apache.excalibur.source.Source;
  +import org.w3c.dom.Document;
  +import org.w3c.dom.Node;
  +
  +/**
  + * This action handles XMLForms for the Artist data
  + */
  +public class ArtistAction extends AbstractXMLFormAction implements
  +      FormListener {
  +  // different form views participating in the form
  +  final String VIEW_START = "start";
  +  final String VIEW_ARTIST = "artist";
  +  final String VIEW_END = "end";
  +  final String VIEW_ERROR = "error";
  +  // action commands used in the wizard
  +  final String CMD_START = "start";
  +  final String CMD_NEXT = "next";
  +  final String CMD_PREV = "prev";
  +  //constant for the XML manipulation, it holds the full name of the
  +  //collection to be used for storing the data
  +  final String xindiceSubCol = "/Artist";
  +
  +  /**
  +   * Extract xmlform-model action parameter and
  +   * instantiate a new form model from it.
  +   *
  +   * In this case it uses a JXPath Container as the model and
  +   * there is no need for a separate model Bean.
  +   *
  +   * @return Form the form object this action works with.
  +   *
  +   */
  +  protected Object getFormModel() {
  +    //to load the XML model
  +    Container DOMModel = null;
  +    Source modelSrc = null;
  +    //this parameter holds the name of the empty XML document
  +    //representing the model
  +    String modelFileName =
  +        getParameters().getParameter("xmlform-model", null);
  +    if(modelFileName==null) return null;
  +    try {
  +      modelSrc = getSourceResolver().resolveURI(modelFileName);
  +      DOMModel = new XMLDocumentContainer(new
  +          StreamSource(modelSrc.getInputStream()));
  +      return DOMModel;
  +    }
  +    catch ( Exception e) {
  +      throw new CascadingRuntimeException(
  +          " Failed instantiating form model ", e );
  +    }
  +    finally {
  +      getSourceResolver().release(modelSrc);
  +    }
  +  }
  +
  +  /**
  +   * Invoked after form population
  +   * Take appropriate action based on the command
  +   *
  +   */
  +  public Map perform () {
  +    // set the page control flow parameter
  +    // according to the validation result
  +    if ( getCommand().equals(CMD_NEXT) &&
  +         getForm().getViolations () != null ) {
  +      // errors, back to the same page
  +      return page( getFormView() );
  +    }
  +    else {
  +      // validation passed
  +      // continue with control flow
  +      // clear validation left overs in case the user
  +      // did not press the Next button
  +      getForm().clearViolations();
  +      // get the user submitted command
  +      String command = getCommand();
  +      // get the form view which was submitted
  +      String formView = getFormView();
  +      // apply control flow rules
  +      if (formView.equals (VIEW_ARTIST)) {
  +        if (command.equals(CMD_NEXT)) {
  +          //extended validation
  +          //test if the ID already exists in the DB
  +          String artistName = (String)getForm().getValue("/Artist/@id");
  +          try {
  +            XindiceManager xi = new XindiceManager();
  +            Node result = xi.find(xindiceSubCol, 
  +                                  "/Artist[@id='"+ artistName +"']",
  +                                  "Artist");
  +           //if we do not get null the element with that ID
  +           //already existed and we add the violation
  +            if (result!=null) {
  +              Violation v = new Violation();
  +              v.setMessage("already exists in the database, 
  +                            please choose another one");
  +              v.setPath("/Artist/@id");
  +              Violation[] va = { v };
  +              getForm().addViolations(Arrays.asList((Object[])va));
  +             //the ID already exists, back to the same
  +             //page to correct the error
  +              return page(VIEW_ARTIST);
  +            }
  +          }
  +          catch (Exception e) {
  +            getLogger().error("Cannot establish a connection to the DB", e);
  +          }
  +          //everything went fine, add the document to the database
  +          try {
  +             addDocument();
  +          }
  +          catch(Exception e) {
  +            //there were errors, send it to the error page
  +            getLogger().error("Cannot add DOM document to the database");
  +            return page(VIEW_ERROR);
  +          }
  +          return page( VIEW_END);
  +
  +       }
  +        if (command.equals(CMD_PREV)) {
  +          return page(VIEW_START);
  +        }
  +      }
  +    }
  +    // should never reach this statement
  +    return page( VIEW_START );
  +  }
  +
  +  /**
  +   * The first callback method which is called
  +   * when an action is invoked.
  +   *
  +   * It is called before population.
  +   * @return null if the Action is ready to continue.
  +   * an objectModel map which will be returned
  +   */
  +  protected Map prepare() {
  +    if ( getCommand() == null ) {
  +      return page(VIEW_START);
  +    }
  +    else if ( getCommand().equals(CMD_START)) {
  +      // reset state by removing old form if one exists
  +      Form.remove( getObjectModel(), getFormId() );
  +      getForm().addFormListener( this );
  +      return page(VIEW_ARTIST);
  +    }
  +    // get ready for action
  +    // if not ready return page("whereNext");
  +    return null;
  +  }
  +
  +  /**
  +   * Add the document to the database
  +   *
  +   */
  +  public void addDocument() throws Exception {
  +    try {
  +      //add the document to the database
  +      XindiceManager xi = new XindiceManager();
  +      //needs the DocumentRoot of the Container as a DOM Node
  +      xi.add(xindiceSubCol, 
  +             ((Document)
  +              (((XMLDocumentContainer)
  +                 (getForm().getModel())).getValue())).getDocumentElement(), 
  +             null);
  +    }
  +    catch (Exception e) {
  +      getLogger().error("DOM Document could not be created", e);
  +      throw e;
  +    }
  +  }
  +}]]></source>
  +        <p>
  +          We had to use an ugly casting mechanism in the
  +          <code>addDocument</code> method but that is what we have by now.
  +          In future JXPath versions this will be easier to accomplish. 
  +        </p>
  +        <s3 title="The helper class">
  +          <p>
  +            In order to make this work we need to use a helper class.
  +            This class uses the XMLDB API to connect to Xindice and make
  +            the operations available to the Action. You should extend it
  +            to add more operations. The helper class
  +            <strong><code>XindiceManager.java</code></strong> is as follows: 
  +          </p>
  +          <source><![CDATA[
  +/**
  + * Helper class for Xindice related operations
  + *
  + */
  +package com.simbiosystems.cocoon.xmlform.xindice.howto;
  +
  +import javax.xml.parsers.DocumentBuilder;
  +import javax.xml.parsers.DocumentBuilderFactory;
  +import org.w3c.dom.DOMImplementation;
  +import org.w3c.dom.Document;
  +import org.w3c.dom.Element;
  +import org.w3c.dom.Node;
  +import org.xmldb.api.DatabaseManager;
  +import org.xmldb.api.base.Collection;
  +import org.xmldb.api.base.Database;
  +import org.xmldb.api.base.Resource;
  +import org.xmldb.api.base.ResourceIterator;
  +import org.xmldb.api.base.ResourceSet;
  +import org.xmldb.api.base.XMLDBException;
  +import org.xmldb.api.modules.XMLResource;
  +import org.xmldb.api.modules.XPathQueryService;
  +
  +public class XindiceManager {
  +
  +  private static final String driver =
  +      "org.apache.xindice.client.xmldb.DatabaseImpl";
  +  private static final String rootCollection = "xmldb:xindice:///db/";
  +
  +  /**
  +   * Constructor
  +   *
  +   */
  +  public XindiceManager() {
  +
  +  }
  +
  +  /**
  +   * Search for a document in the DB. If not found, return null.
  +   *
  +   * @param subCol name of the subCollection to query if any. If blank
  +   * or null, queries go against the rootCollection.
  +   * @param xpath XPath expression for the query, if none, it returns
  +   * the whole Collection
  +   * @param resultRootelement name of the root element for the DOM
  +   * document which will wrap the results
  +   * @return a DOM Node with the matched documents
  +   *
  +   */
  +  public Node find(String subCol, String xpath, String resultRootElement)
  +    throws Exception {
  +
  +    //prepare DOM document
  +    DOMImplementation impl;
  +    DocumentBuilder builder;
  +    try {
  +      // Find the implementation
  +      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  +      factory.setNamespaceAware( false );
  +      factory.setValidating ( false );
  +      builder = factory.newDocumentBuilder();
  +      impl = builder.getDOMImplementation();
  +    }
  +    catch (Exception ex) {
  +      throw new RuntimeException("[XindiceManager.find]: " +
  +          "Failed to initialize DOM factory.  Root cause: \n" + ex);
  +    }
  +    //create the Document which will hold the results
  +    Document resultDoc = impl.createDocument(null, resultRootElement, null);
  +    Node root = resultDoc.getDocumentElement();
  +
  +    //And now the Xindice part
  +    Collection col = null;
  +    String strData = null;
  +
  +    try {
  +      Class c = Class.forName(driver);
  +
  +      Database database = (Database) c.newInstance();
  +      DatabaseManager.registerDatabase(database);
  +
  +      String localCol = rootCollection + subCol;
  +
  +      col = DatabaseManager.getCollection(localCol);
  +
  +      //Make the XPath query and get the resources
  +      XPathQueryService service =
  +        (XPathQueryService) col.getService("XPathQueryService", "1.0");
  +      ResourceSet resultSet = service.query(xpath);
  +      // Iterate the xpath results and add each of them to the main Document
  +      ResourceIterator iterator = resultSet.getIterator();
  +
  +      //if not resources are present, just return null
  +      if(!iterator.hasMoreResources()) return null;
  +
  +      while(iterator.hasMoreResources()) {
  +        Resource r = iterator.nextResource();
  +
  +        Element resElement = 
  +          ((Document)((XMLResource)r).getContentAsDOM()).getDocumentElement();
  +
  +        // Remove unwanted attributes
  +        resElement.removeAttribute("src:col");
  +        resElement.removeAttribute("src:key");
  +        resElement.removeAttribute("xmlns:src");
  +
  +        // Add this result to the root element
  +        Element importedElement =
  +            (Element)resultDoc.importNode(resElement, true);
  +        root.appendChild(importedElement);
  +      }
  +      //return the Document root
  +      return root;
  +    }
  +    catch (Exception e) {
  +      System.err.println("[XindiceManager.find]: Find Exception occured :" + 
  +                          e.getMessage());
  +      throw e;
  +    }
  +    finally {
  +      if (col != null) {
  +        col.close();
  +      }
  +    }
  +  }
  +
  +  /**
  +   * Add a document to the DB. If a key is not passed, it generates a
  +   * unique one.
  +   * This version uses a DOM Document.
  +   * @param subCol name of the subCollection in which to add the resource
  +   * if any. If blank or null, insertions go against the rootCollection.
  +   * @param document DOM document to be inserted
  +   * @param key unique key for the resource to be created.
  +   * If none, one is created on the fly
  +   */
  +  public void add(String subCol, Node document, String key)
  +      throws Exception {
  +    Collection col = null;
  +    Node xmldoc = null;
  +    try {
  +      Class c = Class.forName(driver);
  +
  +      Database database = (Database) c.newInstance();
  +      DatabaseManager.registerDatabase(database);
  +
  +      col = DatabaseManager.getCollection(rootCollection + subCol);
  +
  +      XMLResource document_ = (XMLResource) col.createResource(null,
  +          "XMLResource");
  +      document_.setContentAsDOM(document);
  +      col.storeResource(document_);
  +    }
  +    catch (XMLDBException e) {
  +      System.err.println("[XindiceManager.add]: Add Exception occured " +
  +                         e.errorCode);
  +      throw e;
  +    }
  +    finally {
  +      if (col != null) {
  +        col.close();
  +      }
  +    }
  +  }
  +}]]></source>
  +          <p/>
  +        </s3>
  +      </s2>
  +      <s2 title="5. The Sitemap">
  +        <p>
  +          Remember you should have the <code>XMLFormTransformer</code>
  +          defined like this:
  +        </p>
  +        <source><![CDATA[
  +<map:transformer name="xmlform"
  +                 src="org.apache.cocoon.transformation.XMLFormTransformer" 
  +                 logger="xmlform"/>]]></source>
  +        <p>
  +          Then, you must declare the Action to be used in the
  +          corresponding section: 
  +        </p>
  +        <source><![CDATA[
  +<map:action logger="xmlform" 
  +  name="ArtistAction"
  +  src="com.simbiosystems.cocoon.xmlform.xindice.howto.ArtistAction"/>
  +]]></source>
  +        <p/>
  +        <s3 title="The Pipeline">
  +          <p>
  +            The following pipeline will process requests to our Form:
  +          </p>
  +          <source><![CDATA[
  +<!-- XMLForms<->Xindice pipeline -->
  +<map:pipeline>
  +  <map:match pattern="Artist.xform">
  +    <map:act type="ArtistAction">
  +      <!-- XMLForm parameters for the Action -->
  +      <!-- Notice how we use an XML file as the model -->
  +      <map:parameter name="xmlform-validator-schema-ns" 
  +                     value="http://www.ascc.net/xml/schematron"/>
  +      <map:parameter name="xmlform-validator-schema"
  +                     value="artist/artist-validator.xml"/>
  +      <map:parameter name="xmlform-id" value="artist-insert"/>
  +      <map:parameter name="xmlform-scope" value="session"/>
  +      <map:parameter name="xmlform-model" value="artist/artist-model.xml"/>
  +      <!-- XMLForm document, {page} comes from Action -->
  +      <map:generate src="artist/{page}.xform"/>
  +    </map:act>
  +    <!-- populating the doc with model instance data -->
  +    <map:transform type="xmlform"/>
  +    <!-- look and feel of the form controls  -->
  +    <map:transform src="styles/wizard2html.xsl"/>
  +    <!-- Transforming the XMLForm controls to HTML -->
  +    <map:transform src="styles/xmlform2html.xsl"/>
  +    <!-- sending the HTML back to the browser -->
  +    <map:serialize type="html"/>
  +  </map:match>
  +</map:pipeline>]]></source>
  +          <p>
  +            Depending on where you have Cocoon installed and where you
  +            have configured the files in this how-to, you could make a
  +            request to a URL like
  +            <code>http://localhost:8080/cocoon/Artist.xform</code>
  +            and start using the Form. 
  +          </p>
  +        </s3>
  +      </s2>
  +    </s1>
  +    <s1 title="Final Considerations">
  +      <p>
  +        Making the operations from the Action using the helper class
  +        seems to be the easiest way. You can think of other ways or
  +        other operations using other Xindice tools available in Cocoon
  +        such as the pseudo protocol. For example, you could use it to
  +        query the DB for data that could be stored in a sitemap parameter.
  +        You could then get the data from the Action and use it to fill a
  +        selectbox in the form.
  +      </p>
  +      <p>
  +        We did not mentioned other operations such as updates. This can
  +        be also accomplished this way. For example, if you want to edit
  +        the data we just stored, you could load it in the Container at
  +        the beginning by using the find method of the helper class.
  +        This way you get a filled form in the next step ready for editing.
  +        Other ways or interacting with the repository include the XMLDB
  +        Transformer. Since it uses XUpdate alike syntax, you could format
  +        a XML String for it in the last step of the Action, making it
  +        available to the sitemap then, so the Transformer could get it
  +        and make the operations.
  +      </p>
  +      <p>
  +        We are sure you can think of more different ways and encourage
  +        you to contribute them if you have tested it successfully.
  +        This how-to was refactored quite a bit from an original version
  +        which used a regular Javabean as a wrapper for a DOM Node where
  +        the data were persisted. This new version is much more elegant
  +        and short. If you want to check differences, an
  +        <link 
href="http://wiki.cocoondev.org/Wiki.jsp?page=XMLFormXindiceOldVersion";>old version at 
Cocoon Wiki</link>
  +        still exists.
  +      </p>
  +    </s1>
  +    <s1 title="Summary">
  +      <p>
  +        This How-To makes possible the use of Xindice from XMLForms in
  +        order to add data to the repository. You learned how to connect
  +        to the DB from the Action, and how to make complex validation
  +        using information stored in the DB. Remember that everything you
  +        have just built is reusable for different user agents. You would
  +        only need to use
  +        <link href="../userdocs/concepts/matchers_selectors.html">matchers
  +        and selectors</link> and to choose the appropriate transformation.
  +        We hope this how-to was helpful for you.
  +      </p>
  +    </s1>
  +    <s1 title="References">
  +      <anchor id="references"/>
  +      <p>
  +        This how-to would not be possible without some ideas exchanged
  +        with Ivelin Ivanov in the
  +        <link href="../mail-lists.html">Cocoon Users</link> list and
  +        privately.
  +      </p>
  +    </s1>
  +    <s1 title="Comments">
  +      <p>
  +        Care to comment on this How-To? Got another tip? 
  +        Help keep this How-To relevant by passing along any useful
  +        feedback to the author,
  +        <link href="mailto:josema|at|simbiosystems.com">Josema Alonso</link>
  +        or via the
  +        <link href="../mail-lists.html">Cocoon Users</link> mail list.
  +      </p>
  +    </s1>
  +    <s1 title="Revisions">
  +      <p>
  +        2003-02-04: First version contributed by Josema Alonso.
  +      </p>
  +    </s1>
  +  </body>
  +</document>
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to