You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ibatis.apache.org by gb...@apache.org on 2008/08/04 20:43:44 UTC

svn commit: r682456 [7/7] - in /ibatis/trunk/cs/V3/docs: ./ dataAccessGuide/ dataAccessGuide/resources/ dataAccessGuide/src/ dataAccessGuide/src/en/ dataAccessGuide/src/en/images/ dataAccessGuide/styles/ dataMapperGuide/ dataMapperGuide/resources/ data...

Added: ibatis/trunk/cs/V3/docs/tutorial/src/en/tutorial.xml
URL: http://svn.apache.org/viewvc/ibatis/trunk/cs/V3/docs/tutorial/src/en/tutorial.xml?rev=682456&view=auto
==============================================================================
--- ibatis/trunk/cs/V3/docs/tutorial/src/en/tutorial.xml (added)
+++ ibatis/trunk/cs/V3/docs/tutorial/src/en/tutorial.xml Mon Aug  4 11:43:42 2008
@@ -0,0 +1,1054 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="introduction">
+  <title>iBATIS.NET Data Mapper Tutorial</title>
+
+  <sect1>
+    <title>Introduction</title>
+
+    <sect2>
+      <title>License Information</title>
+
+      <para>iBATIS.NET is licensed according to the terms of the Apache
+      License, Version 2.0. The full text of this license are available online
+      at <ulink
+      url="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</ulink>
+      (<ulink url="http://www.apache.org/licenses/LICENSE-2.0.txt">TXT</ulink>
+      or <ulink
+      url="http://www.apache.org/licenses/LICENSE-2.0.html">HTML</ulink>). You
+      can also view the full text of any of these licenses in the doc
+      subdirectory of the iBATIS.NET distribution.</para>
+    </sect2>
+
+    <sect2>
+      <title>Disclaimer</title>
+
+      <blockquote>
+        <para>iBATIS MAKES NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE
+        INFORMATION IN THIS DOCUMENT. The names of actual companies and
+        products mentioned herein may be the trademarks of their respective
+        owners.</para>
+      </blockquote>
+    </sect2>
+
+    <sect2>
+      <title>Remark</title>
+
+      <para>Original writing by Clinton Begin. Adaptation by Ted Husted and
+      Gilles Bayon with the aimiable permission of Clinton Begin.</para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Welcome</title>
+
+    <para>This tutorial takes an "over-the-shoulder" Cookbook approach. We'll
+    define a simple data access problem and use iBATIS to solve it for
+    us.</para>
+  </sect1>
+
+  <sect1>
+    <title>Test first!</title>
+
+    <para>Let's say that our most important client has a database and one of
+    the tables in the database is a list of people. Our client tells
+    us:</para>
+
+    <para><quote>We would like to use a web application to display the people
+    in this table and to add, edit, and delete individual
+    records.</quote></para>
+
+    <para>Not a complicated story, but it will cover the CRUD most developers
+    want to learn first. :) Let's start with the people table that the client
+    mentioned. Since we're keeping it simple, we'll say it's a table in an
+    Access database. The table definition is shown as Example 1.</para>
+
+    <example>
+      <title>The Person Table</title>
+
+      <programlisting>Name              Type            Size
+PER_ID            Long Integer      4
+PER_FIRST_NAME    Text             40
+PER_LAST_NAME     Text             40
+PER_BIRTH_DATE    Date/Time         8
+PER_WEIGHT_KG     Double            8
+PER_HEIGHT_M      Double            8</programlisting>
+    </example>
+
+    <para>The first thing our story says is that client would like to display
+    a list of people. Example 2 shows our test for that.</para>
+
+    <example>
+      <title>PersonTest.cs</title>
+
+      <programlisting>using System.Collections;
+using IBatisNet.DataMapper;
+using NUnit.Framework;
+
+namespace iBatisTutorial.Model
+{
+ [TestFixture]
+ public class PersonTest
+ {
+  [Test]
+  public void PersonList ()
+  {
+   // try it 
+   IList people = Mapper.Instance().QueryForList("SelectAll",null);
+
+   // test it 
+   Assert.IsNotNull(people,"Person list not returned");
+   Assert.IsTrue(people.Count&gt;0,"Person list is empty"); 
+   Person person = (Person) people[0];
+   Assert.IsNotNull(person,"Person not returned");
+  }
+ }
+}</programlisting>
+    </example>
+
+    <para>Well, Example 2 sure looks easy enough! We ask a method to "select
+    all", and it returns a list of person objects. But, what code do we need
+    to write to pass this test?</para>
+
+    <para>Let's see. The test uses a list of person objects. We could start
+    with a blank object, just to satisfy the test, and add the display
+    properties later. But let's be naughty and skip a step. Our fully-formed
+    person object is shown in Example 3.</para>
+
+    <example>
+      <title>Person.cs</title>
+
+      <programlisting>using System;
+namespace iBatisTutorial.Model
+{
+  public class Person
+  {
+    private int _Id;
+    private string _FirstName;
+    private string _LastName;
+    private DateTime _BirthDate;
+    private double _WeightInKilograms;
+    private double _HeightInMeters;
+
+    public int Id 
+    {
+      get{ return _Id; }
+      set{ _Id = value; }
+    }
+
+// Other public properties for the private fields ...
+
+  }
+}</programlisting>
+    </example>
+
+    <para>OK, that was fun! The Assert class is built into NUnit, so to
+    compile Example 2, we just need the <classname>Mapper</classname> object
+    and <methodname>QueryForList</methodname> method. Wonderfully, the iBATIS
+    DataMapper framework has a <classname>Mapper</classname> class built into
+    it that will work just fine for for us to use in this tutorial, so we
+    don't need to write that either. When the
+    <classname>Mapper.Instance()</classname> method is called, an instance of
+    the iBATIS <classname>SqlMapper</classname> class is returned that has
+    various methods available such as <methodname>QueryForList</methodname>.
+    In this example, the iBATIS
+    <methodname>SqlMapper.QueryForList</methodname> method executes our SQL
+    statement (or stored procedure) and returns the result as a list. Each row
+    in the result becomes an entry in the list. Along with
+    <methodname>QueryForList</methodname>, there are also
+    <methodname>Delete</methodname>, <methodname>Insert</methodname>,
+    <methodname>Select</methodname>, <methodname>QueryForObject</methodname>,
+    <methodname>QueryForPaginatedList</methodname> and a few other methods in
+    the iBATIS API. (See Chapter 4 in the iBATIS DataMapper Developer Guide
+    for details.)</para>
+
+    <para>Looking at Example 2, we see that the
+    <methodname>QueryForList</methodname> method takes the name of the
+    statement we want to run and any runtime values (stored in a parameter
+    object) that the statement may need. Since a "SelectAll" statement
+    wouldn't need any runtime values, we pass null in our test.</para>
+
+    <para>OK. Easy enough. But where does iBATIS get the "SelectAll"
+    statement? Some systems try to generate SQL statements for you, but iBATIS
+    specializes in data mapping, not code generation. It's our job (or the job
+    of our database administrator) to craft the SQL or provide a stored
+    procedure. We then describe the statement in an XML element, like the one
+    shown in Example 4.</para>
+
+    <example>
+      <title>We use XML elements to map a database statement to an application
+      object</title>
+
+      <programlisting>  &lt;typeAlias alias="Person" type="iBatisTutorial.Model.Person, iBatisTutorial.Model" /&gt;
+
+  &lt;resultMap id="SelectResult" class="Person"&gt;
+   &lt;result property="Id" column="PER_ID" /&gt;
+   &lt;result property="FirstName" column="PER_FIRST_NAME" /&gt;
+   &lt;result property="LastName" column="PER_LAST_NAME" /&gt;
+   &lt;result property="BirthDate" column="PER_BIRTH_DATE" /&gt;
+   &lt;result property="WeightInKilograms" column="PER_WEIGHT_KG" /&gt;
+   &lt;result property="HeightInMeters" column="PER_HEIGHT_M" /&gt;
+  &lt;/resultMap&gt;
+
+  &lt;select id="SelectAll" resultMap="SelectResult"&gt;
+   select
+    PER_ID,
+    PER_FIRST_NAME,
+    PER_LAST_NAME,
+    PER_BIRTH_DATE,
+    PER_WEIGHT_KG,
+    PER_HEIGHT_M
+   from PERSON
+  &lt;/select&gt;</programlisting>
+    </example>
+
+    <para><note>
+        <para>Since this is a very simple case, iBATIS could in fact generate
+        this SQL for us. In Example 4, we could have also written the select
+        statement this way: <programlisting>  &lt;select id="SelectAll" resultMap="SelectResult"&gt;
+  &lt;generate table="PERSON" /&gt;
+  &lt;/select&gt;</programlisting></para>
+
+        <para>Using the columns from the ResultMap, iBATIS would generate the
+        SQL statement for us. But this feature only works with the simplest of
+        SQL statements. Most often, you will write your own SQL statement or
+        pass parameters to a stored procedure. (See Section 3 in the
+        DataMapper Developers Guide for more about the generate tag.)</para>
+      </note>The iBATIS mapping documents can hold several sets of related
+    elements, like those shown in Example 4. We can also have as many mapping
+    documents as we need to help organize our code. Additionally, having
+    multiple mapping documents is handy when several developers are working on
+    the project at once.</para>
+
+    <para>So, the framework gets the SQL code for the query from the mapping,
+    and plugs it into a prepared statement. But, how does iBATIS know where to
+    find the table's datasource?</para>
+
+    <para>Surprise! More XML! You can define a configuration file for each
+    datasource your application uses. Example 5 shows a configuration file for
+    our Access database.</para>
+
+    <example>
+      <title>SqlMap.config - a configuration file for our Access
+      database</title>
+
+      <programlisting>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
+&lt;sqlMapConfig
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+  xsi:noNamespaceSchemaLocation="SqlMapConfig.xsd"&gt;
+
+ &lt;properties resource="properties.config"/&gt;
+
+ &lt;settings&gt;
+  &lt;setting useStatementNamespaces="false"/&gt;
+  &lt;setting cacheModelsEnabled="false"/&gt;
+ &lt;/settings&gt;
+
+ &lt;database&gt;
+  &lt;provider name="OleDb1.1"/&gt;
+  &lt;dataSource name="iBatisTutorial"  
+    connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\tutorial\WebView\Resources\iBatisTutorial.mdb"/&gt;
+ &lt;/database&gt;
+
+ &lt;sqlMaps&gt;
+  &lt;sqlMap resource="${root}Resources/PersonHelper.xml"/&gt;
+ &lt;/sqlMaps&gt;
+
+&lt;/sqlMapConfig&gt;</programlisting>
+    </example>
+
+    <para>Of course, besides Access through OLEDB, other ADO.NET providers are
+    supported, including SQL Server, Oracle, MySQL, and generic ODBC
+    providers. (See Section 5 in the Developers Guide for details.)</para>
+
+    <para>The last part of the configuration file ("sqlMaps") is where we list
+    our mapping documents, like the one shown back in Example 4. We can list
+    as many documents as we need here, and they will all be read when the
+    configuration is parsed.</para>
+
+    <para><tip>
+        <para>Did you notice the <varname>${root}</varname> variable placed in
+        the path to PersonHelper.xml? This variable is defined as a
+        "key-value" pair in a <filename>properties.config</filename> file. We
+        are using this properties variable since the application root
+        directory differs by project type (Web, Windows, and library) and can
+        cause lots of headaches when trying to figure out relative paths from
+        that root directory. Typically, the application root directory is
+        where you place your <filename>web.config</filename> or
+        <filename>app.config</filename> file. If we deploy this project as
+        part of an NUnit test library one day and as part of a Web app the
+        next day, we can easily switch our root path from "../../" to "./" in
+        one location, our properties.config file, by using this variable.
+        Otherwise, we would have to change all the relative paths defined in
+        our <filename>SqlMap.config </filename>file. See the DataMapper Guide
+        for more details on using properties files.</para>
+      </tip>OK, so how does the configuration get parsed?</para>
+
+    <para>Look back at Example 2. The heart of the code is the call to the
+    "Mapper" object (under the remark "try it"). The
+    <classname>Mapper</classname> object is a singleton that handles the
+    instantiation and configuration of an iBATIS
+    <classname>SqlMapper</classname> object, which provides a facade to the
+    iBATIS DataMapper framework API. The first time that the
+    <classname>Mapper</classname> is called, it reads in the
+    <filename>sqlMap.config</filename> file and associated mapping documents
+    to create an instance of the <classname>SqlMapper</classname> class. On
+    subsequent calls, it reuses the <classname>SqlMapper</classname> object so
+    that the configuration is re-read only when files change.</para>
+
+    <para>The framework comes bundled with a default
+    <classname>Mapper</classname> class for you to use immediately to get
+    access to the iBATIS <classname>SqlMapper</classname> object. If you want
+    to use a different name other than <filename>sqlMap.config</filename> for
+    the configuration file, or need to use more than one database and have one
+    <classname>SqlMapper</classname> per database, you can also write your own
+    class to mimic the role of the <classname>Mapper</classname> class view by
+    copying and modifying the standard version.</para>
+
+    <para>Example 6 shows the code for the standard
+    <classname>Mapper</classname> class that comes with the framework.</para>
+
+    <example>
+      <title>The standard "Mapper" facade for providing access to the data
+      maps</title>
+
+      <programlisting>using IBatisNet.Common.Utilities;
+using IBatisNet.DataMapper;
+
+namespace IBatisNet.DataMapper
+{
+ public class Mapper
+ {  
+  private static volatile SqlMapper _mapper = null;
+
+  protected static void Configure (object obj)
+  {
+   _mapper = (SqlMapper) obj;
+  }
+
+  protected static void InitMapper()
+  {   
+   ConfigureHandler handler = new ConfigureHandler (Configure);
+   _mapper = SqlMapper.ConfigureAndWatch (handler);
+  }
+
+  public static SqlMapper Instance()
+  {
+   if (_mapper == null)
+   {
+    lock (typeof (SqlMapper))
+    {
+     if (_mapper == null) // double-check
+      InitMapper();
+    }
+   }
+   return _mapper;
+  }
+
+  public static SqlMapper Get()
+  {
+   return Instance();
+  }
+ }
+}</programlisting>
+    </example>
+
+    <para>If you wanted to use a second database, you could load another
+    configuration by changing the call to the
+    <methodname>SqlMapper.ConfigureAndWatch()</methodname> method. There's
+    another method signature that takes a file name, which you can use to
+    specify another configuration, as so:<programlisting>_mapperTwo = SqlMapper.ConfigureAndWatch ("sqlmap2.config", handler);</programlisting>You
+    can access as many different database configurations as you need, just by
+    setting up additional <classname>SqlMapper</classname> instances using
+    different configuration files. Each configured
+    <classname>SqlMapper</classname> instance acts as a facade for accessing a
+    datasource. As far as our application knows, the
+    <classname>SqlMapper</classname> *is* the datasource. Behind the
+    <classname>SqlMapper</classname> facade, you can change the location of
+    the database, or switch between SQL statements and stored procedures, with
+    zero-changes to your application code.</para>
+
+    <para>If we put this all together into a solution, we can "green bar" our
+    test, as shown by Figure 1. If you'd like to see that bar for yourself,
+    open the iBatisNet Tutorial solution available from the website
+    &lt;http://sf.net/projects/ibatisnet&gt;. If you do, you'll note that we
+    set up the solution using two projects. A "Model" project for our business
+    and database code and corresponding unit tests, and a "WebView" project
+    for our user interface. (After extracting the solution, set Web Sharing
+    for the "WebView" folder as "iBatisTutorial". See the ReadMe.txt file
+    included in the solution for other setup instructions.)</para>
+
+    <figure>
+      <title>Green Bar!</title>
+
+      <mediaobject>
+        <imageobject>
+          <imagedata fileref="images/figure01.gif" />
+        </imageobject>
+      </mediaobject>
+    </figure>
+  </sect1>
+
+  <sect1>
+    <title>Playtest second!</title>
+
+    <para>Now that we have a passing test, we setup a page to display our list
+    of people. Example 7 shows the ASPX code for our display page. The key
+    piece is the DataGrid.</para>
+
+    <para><example>
+        <title>ASPX page for our Person list</title>
+
+        <programlisting>&lt;%@ Page language="c#" Codebehind="Person.aspx.cs" AutoEventWireup="false" Inherits="iBatisTutorial.Web.Forms.PersonPage" %&gt;
+&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" &gt; 
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;title&gt;Person&lt;/title&gt;
+    &lt;meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1"&gt;
+    &lt;meta name="CODE_LANGUAGE" Content="C#"&gt;
+    &lt;meta name=vs_defaultClientScript content="JavaScript"&gt;
+    &lt;meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"&gt;
+  &lt;/head&gt;
+  &lt;body&gt;
+    &lt;form id="Person" method="post" runat="server"&gt;
+    &lt;asp:Panel ID="pnlList" Runat="server"&gt;
+      &lt;h1&gt;Person List&lt;/h1&gt;<emphasis>
+        &lt;asp:DataGrid id="dgList" Runat="server"&gt;&lt;/asp:DataGrid&gt;</emphasis>
+    &lt;/asp:Panel&gt;
+    &lt;/form&gt;
+  &lt;/body&gt;
+&lt;/html&gt;</programlisting>
+      </example></para>
+
+    <para>Of course, we still need to populate that DataGrid. Example 8 shows
+    the code-behind. The operative method is
+    <methodname>List_Load</methodname>. The rest is supporting code.</para>
+
+    <example>
+      <title>Code-behind class for our Person list page</title>
+
+      <programlisting>using System;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using IBatisNet.DataMapper;
+
+namespace iBatisTutorial.Web.Forms
+{
+ public class PersonPage : Page
+ {
+
+  #region panel: List 
+
+  protected Panel pnlList;
+  protected DataGrid dgList;
+
+  <emphasis>private void List_Load ()
+  {
+   dgList.DataSource = Mapper.Instance().QueryForList("SelectAll",null);
+   dgList</emphasis>.DataBind();
+  }
+
+  #endregion
+
+  private void Page_Load(object sender, System.EventArgs e)
+  { 
+    if (!IsPostBack)
+   {
+    List_Load ();
+   }
+  }
+
+  #region Web Form Designer generated code
+  override protected void OnInit(EventArgs e)
+  {
+   InitializeComponent();
+   base.OnInit(e);
+  }
+
+  private void InitializeComponent()
+  {    
+   this.Load += new System.EventHandler(this.Page_Load);
+  }
+  #endregion
+ }
+}</programlisting>
+    </example>
+
+    <para>If we run this now, we'll get a list like the one shown in Figure
+    2.</para>
+
+    <figure>
+      <title>A quick-and-dirty Person List</title>
+
+      <mediaobject>
+        <imageobject>
+          <imagedata fileref="images/figure02.gif" />
+        </imageobject>
+      </mediaobject>
+    </figure>
+
+    <para>Not pretty, but at least we have a starting point. The DataGrid is a
+    flexible control, and we can always adjust the column order and headings
+    by changing the ASPX file. The point of this exercise is to get the data
+    to the grid so we can refine it later.</para>
+  </sect1>
+
+  <sect1>
+    <title>Test, test, again ...</title>
+
+    <para>Of course, tweaking the Person List display is not going to be the
+    end of it. Clients always want more, and now ours wants to edit, add, or
+    delete records. Let's write some tests for these new tasks, as shown in
+    Example 9.</para>
+
+    <example>
+      <title>New stories, new tests</title>
+
+      <programlisting>  [Test] 
+  public void PersonUpdate () 
+  { 
+    const string EXPECT = "Clinton";
+    const string EDITED = "Notnilc"; 
+    // get it 
+    Person person = new Person();
+    person.Id = 1; 
+    person = (Person) Mapper.Instance().QueryForObject("Select",1); 
+    // test it
+    Assert.IsNotNull(person,"Missing person");
+    Assert.IsTrue(EXPECT.Equals(person.FirstName),"Mistaken identity");
+    //change it 
+    person.FirstName = EDITED;
+    Mapper.Instance().Update("Update",person); 
+    // get it again some
+    person = (Person) Mapper.Instance().QueryForObject("Select",1); 
+    // test it
+    Assert.IsTrue(EDITED.Equals(person.FirstName),"Same old, same old?"); 
+    // change it back 
+    person.FirstName = EXPECT; 
+    Mapper.Instance().Update("Update",person);       
+  } 
+    
+  [Test] 
+  public void PersonInsertDelete () 
+  { 
+   // insert it 
+   Person person = new Person();
+   person.Id = -1; 
+   Mapper.Instance().Insert("Insert",person); 
+   // delete it
+   int count = Mapper.Instance().Delete("Delete",-1);
+   Assert.IsTrue(count&gt;0,"Nothing to delete"); 
+  }    </programlisting>
+    </example>
+
+    <para>Not the best tests ever written, but for now, they will do :)</para>
+
+    <para>To make the new tests work, we'll need some new mapping statements.
+    Example 10 shows the complete mapper document that we've called
+    <filename>PersonHelper.xml</filename>.</para>
+
+    <example>
+      <title>The new and improved mapper document</title>
+
+      <programlisting>&lt;xml version="1.0" encoding="utf-8" ?&gt; 
+
+&lt;sqlMap 
+ namespace="Person" 
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+ xsi:noNamespaceSchemaLocation="SqlMap.xsd"&gt;
+
+ &lt;alias&gt;
+  &lt;typeAlias alias="Person" type="iBatisTutorial.Model.Person, iBatisTutorial.Model" /&gt;
+ &lt;/alias&gt;
+
+ &lt;resultMaps&gt;
+  &lt;resultMap id="SelectResult" class="Person"&gt;
+   &lt;result property="Id" column="PER_ID" /&gt;
+   &lt;result property="FirstName" column="PER_FIRST_NAME" /&gt;
+   &lt;result property="LastName" column="PER_LAST_NAME" /&gt;
+   &lt;result property="BirthDate" column="PER_BIRTH_DATE" /&gt;
+   &lt;result property="WeightInKilograms" column="PER_WEIGHT_KG" /&gt;
+   &lt;result property="HeightInMeters" column="PER_HEIGHT_M" /&gt;
+  &lt;/resultMap&gt;
+ &lt;/resultMaps&gt;
+
+ &lt;statements&gt;
+
+  &lt;select id="Select" parameterClass="int" resultMap="SelectResult"&gt;
+   select
+    PER_ID,
+    PER_FIRST_NAME,
+    PER_LAST_NAME,
+    PER_BIRTH_DATE,
+    PER_WEIGHT_KG,
+    PER_HEIGHT_M
+    from PERSON
+    &lt;dynamic prepend="WHERE"&gt;
+     &lt;isParameterPresent&gt;
+      PER_ID = #value#
+     &lt;/isParameterPresent&gt;
+    &lt;/dynamic&gt;
+  &lt;/select&gt;
+
+  &lt;insert id="Insert" parameterClass="Person"&gt;
+   insert into PERSON 
+    (PER_ID, PER_FIRST_NAME, PER_LAST_NAME,
+    PER_BIRTH_DATE, PER_WEIGHT_KG, PER_HEIGHT_M)
+   values 
+    (#Id#, #FirstName#, #LastName#, 
+    #BirthDate#, #WeightInKilograms#, #HeightInMeters#)
+  &lt;/insert&gt;
+
+  &lt;update id="Update" parameterClass="Person"&gt;
+   update PERSON set
+    PER_FIRST_NAME = #FirstName#,
+    PER_LAST_NAME = #LastName#, 
+    PER_BIRTH_DATE = #BirthDate#,
+    PER_WEIGHT_KG = #WeightInKilograms#,
+    PER_HEIGHT_M = #HeightInMeters#
+   where PER_ID = #Id#
+  &lt;/update&gt;
+
+  &lt;delete id="Delete" parameterClass="int"&gt;
+   delete from PERSON
+   where PER_ID = #value#
+  &lt;/delete&gt;
+
+ &lt;/statements&gt;
+&lt;/sqlMap&gt;</programlisting>
+    </example>
+
+    <para><note>
+        <para>Of course, the statements in Example 10 are so simple that
+        iBATIS could generate the SQL for us. Since your own applications are
+        liable to be more complex, we continue to use manual SQL in the
+        examples.</para>
+      </note></para>
+
+    <para>Hmm. So, what's with this &lt;isParameterPresent&gt; tag in the
+    &lt;select&gt; element? The &lt;isParameterPresent&gt; tag is an example
+    of Dynamic SQL. Rather than have nearly identical statements for SelectAll
+    and SelectById, we can use Dynamic SQL to let the same statement serve
+    both purposes. If Id is null, the WHERE clause is omitted. Otherwise, the
+    WHERE clause is included. Dynamic SQL is even more useful for "Query By
+    Example" stories. (See Section 3.9 in the DataMapper Developer Guide for
+    more.)</para>
+
+    <para>Why bother? Because with the dynamic clause, we can use a single
+    Select statement for SelectAll or SelectById. Since both invocations are
+    suppose to return the same result, using one statement instead of two
+    reduces redundancy and saves maintenance.</para>
+
+    <para>Well, waddya know, if run our tests now, we are favored with a green
+    bar!. It all works!<note>
+        <para>Though, of course, things usually do not work perfectly the
+        first time! We have to fix this and that, and try, try, again. But
+        NUnit makes trying again quick and easy. For changes to the XML
+        mapping documents, we do not even have to recompile. We can just
+        update the XML and rerun the tests! No muss, no fuss.</para>
+      </note></para>
+
+    <para>Turning back to our ASP.NET page, we can revamp the DataGrid to
+    allow in-place editing and deleting. To add records, we provide a button
+    after the grid that inserts a blank person for client to edit. The ASPX
+    code is shown as Example 11.</para>
+
+    <example>
+      <title>ASPX code for our enhanced DataGrid</title>
+
+      <programlisting>    &lt;asp:DataGrid id="dgList" Runat="server" 
+     AutoGenerateColumns=False
+     DataKeyField="Id"
+     OnEditCommand="List_Edit"
+     OnCancelCommand="List_Cancel"
+     OnUpdateCommand="List_Update"
+     OnDeleteCommand="List_Delete"&gt;
+     &lt;Columns&gt;
+      &lt;asp:BoundColumn DataField="FirstName" HeaderText="First"&gt;&lt;/asp:BoundColumn&gt;
+      &lt;asp:BoundColumn DataField="LastName" HeaderText="Last"&gt;&lt;/asp:BoundColumn&gt;
+      &lt;asp:BoundColumn DataField="HeightInMeters" HeaderText="Height"&gt;&lt;/asp:BoundColumn&gt;
+      &lt;asp:BoundColumn DataField="WeightInKilograms" HeaderText="Weight"&gt;&lt;/asp:BoundColumn&gt;
+      &lt;asp:EditCommandColumn ButtonType="PushButton" EditText="Edit" CancelText="Cancel" UpdateText="Save"&gt;
+      &lt;/asp:EditCommandColumn&gt;
+      &lt;asp:ButtonColumn ButtonType="PushButton" Text="Delete" CommandName="Delete"&gt;
+      &lt;/asp:ButtonColumn&gt;
+     &lt;/Columns&gt;
+    &lt;/asp:DataGrid&gt;
+    &lt;p&gt;&lt;asp:Button ID="btnAdd" Runat="server"&gt;&lt;/asp:Button&gt;&lt;/p&gt;</programlisting>
+    </example>
+
+    <para>Example 12 shows the corresponding methods from the
+    code-behind.</para>
+
+    <example>
+      <title>The code-behind methods for our new DataGrid</title>
+
+      <programlisting> #region panel: List 
+
+  protected Panel pnlList;
+  protected DataGrid dgList;
+  protected Button btnAdd;
+
+  private void List_Init()
+  {
+   btnAdd.Text ="Add New Person";
+   this.btnAdd.Click += new EventHandler(List_Add);
+  }
+
+  private void List_Load ()
+  {
+   dgList.DataSource = Mapper.Instance().QueryForList("Select",null);
+   dgList.DataBind();
+  }
+
+  protected void List_Delete(object source, DataGridCommandEventArgs e)
+  {
+   int id = GetKey(dgList,e);
+   Mapper.Instance().Delete("Delete",id);
+   List_Load();
+  }
+
+  protected void List_Edit(object source, DataGridCommandEventArgs e)
+  {
+   dgList.EditItemIndex = e.Item.ItemIndex;
+   List_Load();
+  }
+
+  protected void List_Update(object source, DataGridCommandEventArgs e)
+  {
+   Person person = new Person();
+   person.Id = GetKey(dgList,e);
+   person.FirstName = GetText(e,0);
+   person.LastName = GetText(e,1);
+   person.HeightInMeters = GetDouble(e,2);
+   person.WeightInKilograms = GetDouble(e,3);
+   Mapper.Instance().Update("Update",person);
+   List_Load();
+  }
+
+  protected void List_Cancel(object source, DataGridCommandEventArgs e)
+  {   
+   dgList.EditItemIndex = -1;
+   List_Load();
+  }
+
+  private int GetKey(DataGrid dg, DataGridCommandEventArgs e)
+  {
+   return (Int32) dg.DataKeys[e.Item.DataSetIndex];
+  }
+
+  private string GetText(DataGridCommandEventArgs e, int v)
+  {
+   return ((TextBox) e.Item.Cells[v].Controls[0]).Text;
+  }
+
+  private double GetDouble(DataGridCommandEventArgs e, int v)
+  {
+   return Convert.ToDouble(GetText(e,v));
+  }
+
+  protected void List_Add (object source, EventArgs e)
+  {
+   Person person = new Person();
+   person.FirstName = "--New Person--";
+   Mapper.Instance().Insert("Insert", person);
+   List_Load ();
+  }
+
+  #endregion
+
+  private void Page_Load(object sender, System.EventArgs e)
+  {
+   List_Init();
+   if (!IsPostBack)
+   {
+    List_Load ();
+   }
+  }
+  
+  // Web Form Designer generated code ...</programlisting>
+    </example>
+
+    <para>OK, we are CRUD complete! There's more we could do here. In
+    particular, we should add validation methods to prevent client from
+    entering alphabetic characters where only numbers can live. But, that's
+    ASP.NET grunt-work, and this is an <emphasis>iBATIS DataMapper</emphasis>
+    tutorial. So, for now, we can stand tall and proudly declare:
+    <emphasis>Mission accomplished!</emphasis></para>
+  </sect1>
+
+  <sect1>
+    <title>Then, refactor</title>
+
+    <para>Well, <emphasis>almost</emphasis> accomplished. The story is
+    complete from client's perspective, but I really don't like spelling out
+    the statement names in so many places. Mistyping the name is a bug waiting
+    to happen. Let's encapsulate the statements we want to call in a helper
+    class, so we only spell out the statement name in one place. Example 13
+    shows our PersonHelper class.<example>
+        <title>PersonHelper.cs - A helper class for accessing the
+        database</title>
+
+        <programlisting>using System.Collections;
+
+namespace iBatisTutorial.Model
+{
+
+ public class PersonHelper : Helper
+ {
+
+  public Person Select(int id)
+  {
+   return (Person) Mapper().QueryForObject("Select",id);
+  }
+
+  public IList SelectAll()
+  {
+   return Mapper().QueryForList("Select",null);
+  }
+
+  public int Insert(Person person)
+  {
+   Mapper().Insert("Insert",person);
+   // Insert is designed so that it can return the new key
+   // but we are not utilizing that feature here
+   return 1;
+  }
+
+  public int Update(Person person)
+  {
+   return Mapper().Update("Update",person);
+  }
+
+  public int Delete(int id)
+  {
+   return Mapper().Delete("Delete",id);
+  }
+
+}</programlisting>
+      </example></para>
+
+    <para>In a larger application, there would be several other "business"
+    objects, like "Person", and several other helper objects. Knowing this, we
+    setup a base Helper class. Our Helper base class, shown in Example 14,
+    provides the Mapper method that hooks up our application with
+    iBATIS.</para>
+
+    <example>
+      <title>Helper.cs -- Our only link to iBATIS</title>
+
+      <programlisting>using IBatisNet.DataMapper;
+
+namespace iBatisTutorial.Model
+{
+ public class Helper
+ {
+  public SqlMapper Mapper ()
+  {
+   return IBatisNet.DataMapper.Mapper.Instance ();
+  }
+ }
+}</programlisting>
+    </example>
+
+    <para>We could now go back and do a straight-forward refactoring.
+    Everywhere we called, say:</para>
+
+    <para><programlisting>Mapper.Get().Update("Update",person);</programlisting></para>
+
+    <para>we could now call:</para>
+
+    <para><programlisting>PersonHelper helper = new PersonHelper(); helper.Update(person);</programlisting></para>
+
+    <para>Hmm. Better in terms of being strongly typed, worse in terms of
+    object management. Now we have to create an instance of PersonHelper to
+    make a data access call. Example 15 shows an alternative solution: Use a
+    singleton to instantiate our helper class one time.</para>
+
+    <example>
+      <title>Helpers.cs - A singleton "concierge" for our Helper
+      classes.</title>
+
+      <programlisting>namespace iBatisTutorial.Model {
+ public class Helpers
+ {
+  private static volatile PersonHelper _PersonHelper = null;
+  public static PersonHelper Person ()
+  {
+   if (_PersonHelper == null)
+   {
+    lock (typeof (PersonHelper))
+    {
+     if (_PersonHelper == null) // double-check
+      _PersonHelper = new PersonHelper();
+    }
+   }
+   return _PersonHelper;
+  }
+ }
+}</programlisting>
+    </example>
+
+    <para>Now if we do a refactoring, we can replace:</para>
+
+    <para><programlisting> Mapper.Instance().Update("Update",person);</programlisting>with</para>
+
+    <para><programlisting> Helpers.Person().Update(person);</programlisting>If
+    we had another helper, say for pets, we could add that to the Helper class
+    and also be able to call:</para>
+
+    <para><programlisting> Helpers.Pet().Update(pet);</programlisting>and so
+    forth. As shown in Figure 3, we can also make full use of Intellisense in
+    selecting both a helper class and its methods.</para>
+
+    <figure>
+      <title>Intellisense works great with our Helper singleton!</title>
+
+      <mediaobject>
+        <imageobject>
+          <imagedata fileref="images/figure03.gif" />
+        </imageobject>
+      </mediaobject>
+    </figure>
+
+    <para>Figure 4 shows the Subversion DIFF report after refactoring for the
+    Helper classes. The lines that changed are emphasized.</para>
+
+    <figure>
+      <title>Refactoring the Person test class</title>
+
+      <programlisting>Index: C:/projects/SourceForge/ibatisnet/Tutorial2/Model/PersonTest.cs
+===================================================================
+--- C:/projects/SourceForge/ibatisnet/Tutorial2/Model/PersonTest.cs (revision 196)
++++ C:/projects/SourceForge/ibatisnet/Tutorial2/Model/PersonTest.cs (working copy)
+@@ -1,5 +1,5 @@
+ using System.Collections;
+-using IBatisNet.DataMapper;
++using iBatisTutorial.Model;
+ using NUnit.Framework;
+ 
+ namespace iBatisTutorial.Model
+@@ -11,7 +11,7 @@
+   public void PersonList ()
+   {
+    // try it 
+<emphasis>-   IList people = Mapper.Instance().QueryForList("Select",null);
++   IList people = Helpers.Person().SelectAll();</emphasis> 
+   // test it 
+   Assert.IsNotNull(people,"Person list not returned");
+@@ -28,7 +28,7 @@
+ 
+    // get it
+    Person person = new Person();
+<emphasis>-   person = (Person) Mapper.Instance().QueryForObject("Select",1);
++   person = Helpers.Person().Select(1);
+</emphasis> 
+    // test it
+    Assert.IsNotNull(person,"Missing person");
+@@ -36,17 +36,17 @@
+ 
+    //change it
+    person.FirstName = EDITED;
+<emphasis>-   Mapper.Instance().Update("Update",person); 
++  Helpers.Person().Update(person);
+</emphasis> 
+    // get it again
+-   Mapper.Instance().Insert("Insert",person); 
++   Helpers.Person().Insert(person);
+<emphasis>-   person = (Person) Mapper.Instance().QueryForObject("Select",1);
++   person = Helpers.Person().Select(1);
+</emphasis> 
+    // test it 
+    Assert.IsTrue(EDITED.Equals(person.FirstName),"Same old, same old?");
+ 
+    // change it back
+    person.FirstName = EXPECT;
+<emphasis>-   Mapper.Instance().Update("Update",person); 
++   Helpers.Person().Update(person);
+</emphasis>   }
+ 
+   [Test]
+@@ -55,9 +55,9 @@
+    // insert it
+    Person person = new Person(); 
+    person.Id = -1; 
+<emphasis>-   Mapper.Instance().Insert("Insert",person); 
++   Helpers.Person().Insert(person);
+</emphasis>    // delete it
+<emphasis>-   int count = Mapper.Instance().Delete("Delete",-1);
++   int count = Helpers.Person().Delete(person.Id);
+</emphasis>    Assert.IsTrue(count&gt;0,"Nothing to delete"); 
+   }
+ }</programlisting>
+    </figure>
+
+    <para>Now, all our references are to our own Helper singleton rather than
+    the iBATIS Mapper class. Figure 5 shows the same type of DIFF report for
+    our ASP.NET code-behind file. The ASP.NET page is unchanged. (Ahh,the
+    beauty of code-behind!)</para>
+
+    <figure>
+      <title>Refactoring the Person list code-behind class.</title>
+
+      <programlisting>Index: C:/projects/SourceForge/ibatisnet/Tutorial2/WebView/Forms/Person.aspx.cs
+===================================================================
+--- C:/projects/SourceForge/ibatisnet/Tutorial2/WebView/Forms/Person.aspx.cs (revision 196)
++++ C:/projects/SourceForge/ibatisnet/Tutorial2/WebView/Forms/Person.aspx.cs (working copy)
+@@ -1,13 +1,10 @@
+ using System;
+ using System.Web.UI;
+ using System.Web.UI.WebControls;
+-using IBatisNet.DataMapper;
+ using iBatisTutorial.Model;
+ 
+ namespace iBatisTutorial.Web.Forms
+ {
+  public class PersonPage : Page
+  {
+ 
+@@ -25,14 +22,14 @@
+ 
+   private void List_Load ()
+   {
+<emphasis>-   dgList.DataSource = Mapper.Instance().QueryForList("Select",null);
++   dgList.DataSource = Helpers.Person().SelectAll();
+</emphasis>    dgList.DataBind();
+   }
+ 
+   protected void List_Delete(object source, DataGridCommandEventArgs e)
+   {
+    int id = GetKey(dgList,e);
+<emphasis>-   Mapper.Instance().Delete("Delete",id);
++   Helpers.Person().Delete(id);
+</emphasis>    List_Load();
+   }
+ 
+@@ -50,7 +47,7 @@
+     person.LastName = GetText(e,1);
+     person.HeightInMeters = GetDouble(e,2);
+     person.WeightInKilograms = GetDouble(e,3);
+<emphasis>-   Mapper.Instance().Update("Update",person);
++   Helpers.Person().Update(person);
+</emphasis>    List_Load();
+   }
+ 
+@@ -79,7 +76,7 @@
+   {
+    Person person = new Person();
+    person.FirstName = "--New Person--";
+<emphasis>-   Mapper.Instance().Insert("Insert",person);
++   Helpers.Person().Insert(person);
+</emphasis>    List_Load();
+   }</programlisting>
+    </figure>
+
+    <para>Note that adding the Helper singleton let us remove all iBATIS
+    framework semantics from the Test and code-behind classes. Looking at the
+    classes, you can't tell what data persistence system (if any) is being
+    used. All you see is a call to some Helper. In my book, that's a good
+    thing!</para>
+
+    <para>Now I'm happy, and ready to move on to the next story ... As for
+    you, if you've liked what you've seen so far, please move on to the
+    DataMapper Developers Guide. There are many more goodies in store.</para>
+  </sect1>
+</chapter>
\ No newline at end of file

Added: ibatis/trunk/cs/V3/docs/tutorial/styles/fopdf.xsl
URL: http://svn.apache.org/viewvc/ibatis/trunk/cs/V3/docs/tutorial/styles/fopdf.xsl?rev=682456&view=auto
==============================================================================
--- ibatis/trunk/cs/V3/docs/tutorial/styles/fopdf.xsl (added)
+++ ibatis/trunk/cs/V3/docs/tutorial/styles/fopdf.xsl Mon Aug  4 11:43:42 2008
@@ -0,0 +1,538 @@
+<?xml version="1.0"?>
+
+<!-- 
+
+    This is the XSL FO configuration file for the Hibernate
+    Reference Documentation. It defines a custom titlepage and
+    the parameters for the A4 sized PDF printable output.
+    
+    It took me days to figure out this stuff and fix most of
+    the obvious bugs in the DocBook XSL distribution, so if you
+    use this stylesheet, give some credit back to the Hibernate
+    project.
+    
+    christian.bauer@bluemars.de
+-->
+
+<!DOCTYPE xsl:stylesheet [
+    <!ENTITY db_xsl_path        "../../docbook/">
+    <!ENTITY admon_gfx_path     "../../docbook/images">
+]>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0"
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                xmlns:fo="http://www.w3.org/1999/XSL/Format"
+                exclude-result-prefixes="#default">
+                
+<xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
+
+<xsl:param name="draft.watermark.image" select="'&db_xsl_path;/images/draft.png'"/>
+
+<!--###################################################
+                   Custom Title Page
+    ################################################### --> 
+    
+    <xsl:template name="book.titlepage.recto">
+        <fo:block>
+            <fo:table table-layout="fixed" width="175mm">
+                <fo:table-column column-width="175mm"/>
+                <fo:table-body>
+                    <fo:table-row>
+                        <fo:table-cell text-align="center">
+                             <fo:block>
+                                <fo:external-graphic src="file:images/ibatisnet.gif"/>
+                            </fo:block> 
+                            <fo:block font-family="Helvetica" font-size="22pt" padding-before="10mm">
+                                <xsl:value-of select="bookinfo/subtitle"/> 
+                            </fo:block>
+                            <fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
+                                <xsl:value-of select="bookinfo/releaseinfo"/>  
+                            </fo:block>
+                        </fo:table-cell>
+                    </fo:table-row>
+                    <fo:table-row>
+                        <fo:table-cell text-align="center">
+                            <fo:block font-family="Helvetica" font-size="14pt" padding="10mm">
+                                <xsl:value-of select="bookinfo/pubdate"/> 
+                            </fo:block>
+                        </fo:table-cell>
+                    </fo:table-row>
+                    <fo:table-row>
+                        <fo:table-cell text-align="center">
+							<fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
+                                <xsl:text>Copyright 2003-2005 The Apache Software Foundation</xsl:text>
+                            </fo:block>
+							 <fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
+                                <xsl:text>Authors - </xsl:text>
+                                <xsl:for-each select="bookinfo/authorgroup/author">
+                                    <xsl:if test="position() > 1">
+                                        <xsl:text>, </xsl:text>
+                                    </xsl:if>
+                                    <xsl:value-of select="firstname"/>
+                                    <xsl:text> </xsl:text>
+                                    <xsl:value-of select="surname"/>
+                                </xsl:for-each>
+                            </fo:block>
+                            <fo:block font-family="Helvetica" font-size="10pt" padding="1mm">
+                                <xsl:value-of select="bookinfo/legalnotice"/>  
+                            </fo:block>
+                        </fo:table-cell>
+                    </fo:table-row>
+                </fo:table-body>
+            </fo:table>
+        </fo:block>
+    </xsl:template>
+
+    <!-- Prevent blank pages in output -->    
+    <xsl:template name="book.titlepage.before.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.verso">
+    </xsl:template>
+    <xsl:template name="book.titlepage.separator">
+    </xsl:template>
+        
+<!--###################################################
+                      Header
+    ################################################### -->  
+
+    <!-- More space in the center header for long text -->
+    <xsl:attribute-set name="header.content.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$body.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="margin-left">-5em</xsl:attribute>
+        <xsl:attribute name="margin-right">-5em</xsl:attribute>
+    </xsl:attribute-set>
+
+<!--###################################################
+                      Custom Footer
+    ################################################### -->     
+
+    <!-- This footer prints the Spring Framework version number on the left side -->
+    <xsl:template name="footer.content">
+        <xsl:param name="pageclass" select="''"/>
+        <xsl:param name="sequence" select="''"/>
+        <xsl:param name="position" select="''"/>
+        <xsl:param name="gentext-key" select="''"/>
+
+        <xsl:variable name="Version">
+            <xsl:choose>
+                <xsl:when test="//releaseinfo">
+                        <xsl:text>DataMapper Turorial</xsl:text><xsl:value-of select="//releaseinfo"/>
+                </xsl:when>
+                <xsl:otherwise>
+                    <!-- nop -->
+                </xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
+        <xsl:choose>
+            <xsl:when test="$sequence='blank'">
+            <xsl:choose>
+                <xsl:when test="$double.sided != 0 and $position = 'left'">
+                <xsl:value-of select="$Version"/>
+                </xsl:when>
+
+                <xsl:when test="$double.sided = 0 and $position = 'center'">
+                <!-- nop -->
+                </xsl:when>
+
+                <xsl:otherwise>
+                <fo:page-number/>
+                </xsl:otherwise>
+            </xsl:choose>
+            </xsl:when>
+
+            <xsl:when test="$pageclass='titlepage'">
+            <!-- nop: other titlepage sequences have no footer -->
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
+            <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
+            <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='right'">
+            <fo:page-number/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
+            <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
+            <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:when test="$double.sided = 0 and $position='left'">
+            <xsl:value-of select="$Version"/>
+            </xsl:when>
+
+            <xsl:otherwise>
+            <!-- nop -->
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>    
+    
+<!--###################################################
+                   Custom Toc Line
+    ################################################### -->
+    
+    <!-- The default DocBook XSL TOC printing is seriously broken... -->
+    <xsl:template name="toc.line">
+        <xsl:variable name="id">
+            <xsl:call-template name="object.id"/>
+        </xsl:variable>
+
+        <xsl:variable name="label">
+            <xsl:apply-templates select="." mode="label.markup"/>
+        </xsl:variable>
+
+        <!-- justify-end removed from block attributes (space problem in title.markup) -->
+        <fo:block  end-indent="{$toc.indent.width}pt"
+                   last-line-end-indent="-{$toc.indent.width}pt"
+                   white-space-treatment="preserve"
+                   text-align="left"
+                   white-space-collapse="false">
+            <fo:inline keep-with-next.within-line="always">
+                <!-- print Chapters in bold style -->
+                <xsl:choose>
+                    <xsl:when test="local-name(.) = 'chapter'">
+                        <xsl:attribute name="font-weight">bold</xsl:attribute>
+                    </xsl:when>
+                </xsl:choose>        
+                <fo:basic-link internal-destination="{$id}">
+                    <xsl:if test="$label != ''">
+                        <xsl:copy-of select="$label"/>
+                        <fo:inline white-space-treatment="preserve"
+                                    white-space-collapse="false">
+                            <xsl:value-of select="$autotoc.label.separator"/>
+                        </fo:inline>
+                    </xsl:if>
+                    <xsl:apply-templates select="." mode="title.markup"/>
+                </fo:basic-link>
+            </fo:inline>
+            <fo:inline keep-together.within-line="always">
+            <xsl:text> </xsl:text>
+            <fo:leader leader-pattern="dots"
+                        leader-pattern-width="3pt"
+                        leader-alignment="reference-area"
+                        keep-with-next.within-line="always"/>
+            <xsl:text> </xsl:text>
+            <fo:basic-link internal-destination="{$id}">
+                <fo:page-number-citation ref-id="{$id}"/>
+            </fo:basic-link>
+            </fo:inline>
+        </fo:block>
+    </xsl:template>
+    
+<!--###################################################
+                      Extensions
+    ################################################### -->  
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <!-- FOP provide only PDF Bookmarks at the moment -->
+    <xsl:param name="fop.extensions">1</xsl:param>
+
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">2</xsl:param>
+    
+    <!-- Dot and Whitespace as separator in TOC between Label and Title-->
+    <xsl:param name="autotoc.label.separator" select="'.  '"/>
+
+        
+<!--###################################################
+                   Paper & Page Size
+    ################################################### -->  
+    
+    <!-- Paper type, no headers on blank pages, no double sided printing -->
+    <xsl:param name="paper.type" select="'A4'"/>
+    <xsl:param name="double.sided">0</xsl:param>
+    <xsl:param name="headers.on.blank.pages">0</xsl:param>
+    <xsl:param name="footers.on.blank.pages">0</xsl:param>
+
+    <!-- Space between paper border and content (chaotic stuff, don't touch) -->
+    <xsl:param name="page.margin.top">5mm</xsl:param>
+    <xsl:param name="region.before.extent">10mm</xsl:param>
+    <xsl:param name="body.margin.top">10mm</xsl:param>
+    
+    <xsl:param name="body.margin.bottom">15mm</xsl:param>
+    <xsl:param name="region.after.extent">10mm</xsl:param>
+    <xsl:param name="page.margin.bottom">0mm</xsl:param>
+    
+    <xsl:param name="page.margin.outer">18mm</xsl:param>
+    <xsl:param name="page.margin.inner">18mm</xsl:param>
+
+    <!-- No intendation of Titles -->
+    <xsl:param name="title.margin.left">0pc</xsl:param>
+
+<!--###################################################
+                   Fonts & Styles
+    ################################################### -->      
+
+    <!-- Justified text and no hyphenation -->
+    <xsl:param name="alignment">left</xsl:param>
+    <xsl:param name="hyphenate">false</xsl:param>
+
+    <!-- Default Font size -->
+    <xsl:param name="body.font.master">11</xsl:param>
+    <xsl:param name="body.font.small">8</xsl:param>
+
+    <!-- Line height in body text -->
+    <xsl:param name="line-height">1.4</xsl:param>
+
+    <!-- Monospaced fonts are smaller than regular text -->
+    <xsl:attribute-set name="monospace.properties">
+        <xsl:attribute name="font-family">
+            <xsl:value-of select="$monospace.font.family"/>
+        </xsl:attribute>
+        <xsl:attribute name="font-size">0.8em</xsl:attribute>
+    </xsl:attribute-set>
+    
+<!--###################################################
+                   Tables
+    ################################################### -->
+
+    <!-- The table width should be adapted to the paper size -->
+    <xsl:param name="default.table.width">17.4cm</xsl:param>
+
+    <!-- Some padding inside tables -->    
+    <xsl:attribute-set name="table.cell.padding">
+        <xsl:attribute name="padding-left">4pt</xsl:attribute>
+        <xsl:attribute name="padding-right">4pt</xsl:attribute>
+        <xsl:attribute name="padding-top">4pt</xsl:attribute>
+        <xsl:attribute name="padding-bottom">4pt</xsl:attribute>
+    </xsl:attribute-set>
+    
+    <!-- Only hairlines as frame and cell borders in tables -->
+    <xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
+    <xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
+        
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+<!--###################################################
+                         Titles
+    ################################################### -->   
+    
+    <!-- Chapter title size -->
+    <xsl:attribute-set name="chapter.titlepage.recto.style">
+        <xsl:attribute name="text-align">left</xsl:attribute>
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.8"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>        
+    </xsl:attribute-set>
+
+    <!-- Why is the font-size for chapters hardcoded in the XSL FO templates? 
+        Let's remove it, so this sucker can use our attribute-set only... -->
+    <xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
+        <fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
+                  xsl:use-attribute-sets="chapter.titlepage.recto.style">
+            <xsl:call-template name="component.title">
+                <xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
+            </xsl:call-template>
+            </fo:block>
+    </xsl:template>
+    
+    <!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->    
+    <xsl:attribute-set name="section.title.level1.properties">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.5"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level2.properties">
+        <xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.25"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+    <xsl:attribute-set name="section.title.level3.properties">
+        <xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master * 1.0"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+    <!-- Titles of formal objects (tables, examples, ...) -->
+    <xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
+        <xsl:attribute name="font-weight">bold</xsl:attribute>
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.master"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+        <xsl:attribute name="hyphenate">false</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
+    </xsl:attribute-set>    
+
+<!--###################################################
+                      Programlistings
+    ################################################### -->  
+    
+    <!-- Verbatim text formatting (programlistings) -->
+    <xsl:attribute-set name="monospace.verbatim.properties">
+        <xsl:attribute name="font-size">
+            <xsl:value-of select="$body.font.small * 1.0"/>
+            <xsl:text>pt</xsl:text>
+        </xsl:attribute>
+    </xsl:attribute-set>
+    
+    <xsl:attribute-set name="verbatim.properties">
+        <xsl:attribute name="space-before.minimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.optimum">1em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">1em</xsl:attribute>
+        <!-- alef: commented out because footnotes were screwed because of it -->
+        <!--<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>-->
+        <xsl:attribute name="border-color">#444444</xsl:attribute>
+        <xsl:attribute name="border-style">solid</xsl:attribute>
+        <xsl:attribute name="border-width">0.1pt</xsl:attribute>      
+        <xsl:attribute name="padding-top">0.5em</xsl:attribute>      
+        <xsl:attribute name="padding-left">0.5em</xsl:attribute>      
+        <xsl:attribute name="padding-right">0.5em</xsl:attribute>      
+        <xsl:attribute name="padding-bottom">0.5em</xsl:attribute>      
+        <xsl:attribute name="margin-left">0.5em</xsl:attribute>      
+        <xsl:attribute name="margin-right">0.5em</xsl:attribute>      
+    </xsl:attribute-set>    
+
+    <!-- Shade (background) programlistings -->    
+    <xsl:param name="shade.verbatim">1</xsl:param>
+    <xsl:attribute-set name="shade.verbatim.style">
+        <xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
+    </xsl:attribute-set>
+                    
+<!--###################################################
+                         Callouts
+    ################################################### -->   
+
+    <!-- Use images for callouts instead of (1) (2) (3) -->
+    <xsl:param name="callout.graphics">0</xsl:param>
+    <xsl:param name="callout.unicode">1</xsl:param>
+    
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                       Admonitions
+    ################################################### -->   
+
+    <!-- Use nice graphics for admonitions -->
+    <xsl:param name="admon.graphics">'1'</xsl:param>
+    <xsl:param name="admon.graphics.path">&admon_gfx_path;</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>
+    
+    <!-- Format Variable Lists as Blocks (prevents horizontal overflow) -->
+    <xsl:param name="variablelist.as.blocks">1</xsl:param>
+
+    <!-- The horrible list spacing problems -->
+    <xsl:attribute-set name="list.block.spacing">
+        <xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
+        <xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
+        <xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
+    </xsl:attribute-set>
+
+	<xsl:template match="emphasis[@role='comment']">
+	  <fo:inline color="green">
+		<xsl:apply-imports/>
+	  </fo:inline>
+	</xsl:template>
+
+	<xsl:template match="emphasis[@role='blue']">
+	  <fo:inline color="blue" font-weight="bold">
+		<xsl:apply-imports/>
+	  </fo:inline>
+	</xsl:template>
+
+    <!-- Newer DocBook XSL apparently thinks that some sections are by
+         default "draft" status, and this idiotic thing is by default
+         also set to "maybe", so it spits out a lot of errors with the
+         latest FOP as the XSL/FO styles have references to some draft
+         watermarks, which you actually don't want in the first place.
+         Turn this crap off. If you have to work with the "status"
+         attribute, don't.
+    -->
+    <xsl:param name="draft.mode" select="'no'"/>
+
+    <!-- Format Header table 
+	<xsl:template match="thead">
+		<xsl:variable name="tgroup" select="parent::*"/>
+	 
+		  <fo:table-header>
+			<xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
+			<xsl:attribute name="font-weight">bold</xsl:attribute>
+			<xsl:attribute name="border-left-color">#000000</xsl:attribute>
+			<xsl:attribute name="border-right-color">#000000</xsl:attribute>
+			<xsl:attribute name="border-top-color">#000000</xsl:attribute>
+			<xsl:apply-templates select="row[1]">
+			  <xsl:with-param name="spans">
+				<xsl:call-template name="blank.spans">
+				  <xsl:with-param name="cols" select="../@cols"/>
+				</xsl:call-template>
+			  </xsl:with-param>
+			</xsl:apply-templates>
+		  </fo:table-header>
+	</xsl:template>-->
+
+
+
+</xsl:stylesheet>

Added: ibatis/trunk/cs/V3/docs/tutorial/styles/html.css
URL: http://svn.apache.org/viewvc/ibatis/trunk/cs/V3/docs/tutorial/styles/html.css?rev=682456&view=auto
==============================================================================
--- ibatis/trunk/cs/V3/docs/tutorial/styles/html.css (added)
+++ ibatis/trunk/cs/V3/docs/tutorial/styles/html.css Mon Aug  4 11:43:42 2008
@@ -0,0 +1,225 @@
+body { 
+    background: #FFFFFF; 
+	font-family: sans-serif; 
+	scrollbar-arrow-color: #000000;
+	scrollbar-base-color: #003300;
+	scrollbar-dark-shadow-color: #999900;
+	scrollbar-track-color: #808080;
+	scrollbar-face-color: #DEDEDE;
+	scrollbar-shadow-color: #DDDDDD;
+	scrollbar-highlight-color: #CCCCCC;
+	scrollbar-3d-light-color: #003300;
+}
+
+
+A:link{COLOR: #5E741C; TEXT-DECORATION: underline;}
+A:visited{COLOR: #5E741C; TEXT-DECORATION: underline;}
+A:hover{COLOR: #FF6600; TEXT-DECORATION: underline;}
+
+P, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+    margin-bottom: 3px;
+    margin-top: 3px;
+    padding-top: 0px;
+    text-align: left;
+    /*border: 1px solid black;*/
+}
+
+OL, UL, P {
+    margin-top: 6px;
+    margin-bottom: 6px;
+}
+
+P, BLOCKQUOTE {
+    font-size: 90%;
+}
+
+P.releaseinfo {
+    font-size: 120%; font-weight: bold; 
+    font-family: Arial, helvetica, sans-serif;
+    padding-top: 10px;
+}
+
+P.pubdate {
+    font-size: 120%; font-weight: bold; 
+    font-family: Arial, helvetica, sans-serif;
+}
+
+
+
+TD, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+H1, H2, H3, H4, H5, H6    {
+    margin-top:0px;
+    padding-top:14px;
+    font-family: Arial, helvetica, sans-serif;
+    margin-bottom: 0px;
+}
+
+H2.title {
+    font-weight:800;
+    margin-bottom: 8px;
+}
+
+H2.subtitle {
+    font-weight:800;
+    margin-bottom: 20px;
+}
+
+H3.author {
+    color: #000000;
+    font-weight:500;
+    margin-top:0px;
+    padding-top:0px;
+    font-family: Arial, helvetica, sans-serif;
+    margin-bottom: 0px;
+}
+
+TABLE  {
+    border-collapse: collapse;
+    border: 1px thin #eeeeee;
+    empty-cells: hide;
+	border-style : groove;
+	border-spacing: 0px;
+}
+
+TH {
+    background-color: #EBEBEC;
+}
+
+td {
+border : 2px; 
+border-color : #eeeeee; 
+border-style : groove;
+border-spacing: 0px;
+font-size: 80%;
+ padding: 4pt;
+}
+
+
+H1 { 
+    font-size: 150%; 
+}
+H2 { 
+    font-size: 110%; 
+}
+H3 {
+    font-size: 100%; font-weight: bold; 
+}
+H4 { 
+    font-size: 90%; font-weight: bold;
+}
+H5 {
+    font-size: 90%; font-style: italic; 
+}
+H6 { 
+    font-size: 100%; font-style: italic; 
+}
+
+TT {
+    font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+.navheader, .navfooter {    
+    background-color: #ffffff;
+}
+.navheader TABLE {    
+    background-color: #D4D5D8;
+}
+.navheader th {    
+    background-color: #D4D5D8;
+}
+.navheader td {    
+    border : 0px; 
+}
+.navfooter TABLE {    
+    background-color: #D4D5D8;
+}
+.navfooter th {    
+    background-color: #D4D5D8;
+}
+.navfooter td {    
+    border : 0px; 
+}
+
+PRE {
+    font-size: 90%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+/*(.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}*/
+
+.term { 
+    font-weight:bold;
+}
+
+.mediaobject {
+    padding-top: 30px; 
+    padding-bottom: 30px; 
+}
+
+.legalnotice {
+    font-size: 70%;
+}
+  
+
+.sidebar {
+	background-color: #E5ECF9;
+	padding: 0.25cm;
+}
+
+.programlisting {
+    font-family: courier;
+    font-size: 11px;
+    font-weight: normal;
+    font-family: Lucida Console, monospace;
+    background-color: #EEEEEE;
+    padding: 0.25cm;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC
+ }
+
+.comment {
+	color: #008000;
+}
+
+.blue {
+	color: #0000FF;
+	font-weight: bold; 
+}
\ No newline at end of file

Added: ibatis/trunk/cs/V3/docs/tutorial/styles/html.xsl
URL: http://svn.apache.org/viewvc/ibatis/trunk/cs/V3/docs/tutorial/styles/html.xsl?rev=682456&view=auto
==============================================================================
--- ibatis/trunk/cs/V3/docs/tutorial/styles/html.xsl (added)
+++ ibatis/trunk/cs/V3/docs/tutorial/styles/html.xsl Mon Aug  4 11:43:42 2008
@@ -0,0 +1,70 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	        version="1.0">
+	<xsl:import href="../../docbook/htmlhelp/htmlhelp.xsl"/>
+
+<!--###################################################
+                     HTML Settings
+    ################################################### -->  
+	<xsl:param name="html.stylesheet" select="'html.css'"/>
+
+    <!-- These extensions are required for table printing and other stuff -->
+    <xsl:param name="use.extensions">1</xsl:param>
+    <xsl:param name="tablecolumns.extension">0</xsl:param>
+    <xsl:param name="callout.extensions">1</xsl:param>
+    <xsl:param name="graphicsize.extension">0</xsl:param>
+
+<!--###################################################
+                      Table Of Contents
+    ################################################### -->   
+
+    <!-- Generate the TOCs for named components only -->
+    <xsl:param name="generate.toc">
+        book   toc
+    </xsl:param>
+    
+    <!-- Show only Sections up to level 3 in the TOCs -->
+    <xsl:param name="toc.section.depth">5</xsl:param>
+    <xsl:param name="generate.index" select="1"></xsl:param>
+
+<!--###################################################
+                         Labels
+    ################################################### -->   
+
+    <!-- Label Chapters and Sections (numbering) -->
+    <xsl:param name="chapter.autolabel">1</xsl:param>
+    <xsl:param name="section.autolabel" select="1"/>
+    <xsl:param name="section.label.includes.component.label" select="1"/>
+
+<!--###################################################
+                         Callouts
+    ################################################### -->   
+
+    <!-- Use images for callouts instead of (1) (2) (3) -->
+
+	<xsl:param name="admon.graphics" select="1"/>
+	<xsl:param name="admon.graphics.path">images/</xsl:param>
+    
+    <!-- Place callout marks at this column in annotated areas -->
+    <xsl:param name="callout.defaultcolumn">90</xsl:param>
+
+<!--###################################################
+                          Misc
+    ################################################### -->   
+
+    <!-- Placement of titles -->
+    <xsl:param name="formal.title.placement">
+        figure after
+        example before
+        equation before
+        table before
+        procedure before
+    </xsl:param>   
+
+	<xsl:param name="generate.legalnotice.link" select="1"/>
+	<xsl:param name="suppress.navigation" select="0"/>
+
+	<xsl:param name="htmlhelp.hhc.binary" select="0"/>
+	<xsl:param name="htmlhelp.hhc.folders.instead.books" select="0"/>
+	<xsl:param name="htmlhelp.chm" select="'doc.chm'"/>
+
+</xsl:stylesheet>
\ No newline at end of file

Added: ibatis/trunk/cs/V3/docs/xsltproc/readme.txt
URL: http://svn.apache.org/viewvc/ibatis/trunk/cs/V3/docs/xsltproc/readme.txt?rev=682456&view=auto
==============================================================================
--- ibatis/trunk/cs/V3/docs/xsltproc/readme.txt (added)
+++ ibatis/trunk/cs/V3/docs/xsltproc/readme.txt Mon Aug  4 11:43:42 2008
@@ -0,0 +1,20 @@
+This directory is where we'll hold the xsltproc libraries.
+
+Windows
+=======
+To install on a Windows machine one needs to download the Windows binaries and libraries. 
+These can be obtained from http://www.zlatkovic.com/pub/libxml/ or ftp://xmlsoft.org/win32/. 
+Download the following: 
+ 
+  
+ iconv-1.9.1.win32.zip 
+ libxml2-2.6.15.win32.zip 
+ libxmlsec-1.2.6.win32.zip 
+ libxslt-1.1.12.win32.zip 
+ zlib-1.2.1.win32.zip 
+
+Unzip all and put the content in the directoty.
+ 
+
+
+