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>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> <typeAlias alias="Person" type="iBatisTutorial.Model.Person, iBatisTutorial.Model" />
+
+ <resultMap id="SelectResult" class="Person">
+ <result property="Id" column="PER_ID" />
+ <result property="FirstName" column="PER_FIRST_NAME" />
+ <result property="LastName" column="PER_LAST_NAME" />
+ <result property="BirthDate" column="PER_BIRTH_DATE" />
+ <result property="WeightInKilograms" column="PER_WEIGHT_KG" />
+ <result property="HeightInMeters" column="PER_HEIGHT_M" />
+ </resultMap>
+
+ <select id="SelectAll" resultMap="SelectResult">
+ select
+ PER_ID,
+ PER_FIRST_NAME,
+ PER_LAST_NAME,
+ PER_BIRTH_DATE,
+ PER_WEIGHT_KG,
+ PER_HEIGHT_M
+ from PERSON
+ </select></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> <select id="SelectAll" resultMap="SelectResult">
+ <generate table="PERSON" />
+ </select></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><?xml version="1.0" encoding="UTF-8" ?>
+<sqlMapConfig
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="SqlMapConfig.xsd">
+
+ <properties resource="properties.config"/>
+
+ <settings>
+ <setting useStatementNamespaces="false"/>
+ <setting cacheModelsEnabled="false"/>
+ </settings>
+
+ <database>
+ <provider name="OleDb1.1"/>
+ <dataSource name="iBatisTutorial"
+ connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\tutorial\WebView\Resources\iBatisTutorial.mdb"/>
+ </database>
+
+ <sqlMaps>
+ <sqlMap resource="${root}Resources/PersonHelper.xml"/>
+ </sqlMaps>
+
+</sqlMapConfig></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
+ <http://sf.net/projects/ibatisnet>. 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><%@ Page language="c#" Codebehind="Person.aspx.cs" AutoEventWireup="false" Inherits="iBatisTutorial.Web.Forms.PersonPage" %>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
+<html>
+ <head>
+ <title>Person</title>
+ <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
+ <meta name="CODE_LANGUAGE" Content="C#">
+ <meta name=vs_defaultClientScript content="JavaScript">
+ <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
+ </head>
+ <body>
+ <form id="Person" method="post" runat="server">
+ <asp:Panel ID="pnlList" Runat="server">
+ <h1>Person List</h1><emphasis>
+ <asp:DataGrid id="dgList" Runat="server"></asp:DataGrid></emphasis>
+ </asp:Panel>
+ </form>
+ </body>
+</html></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>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><xml version="1.0" encoding="utf-8" ?>
+
+<sqlMap
+ namespace="Person"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="SqlMap.xsd">
+
+ <alias>
+ <typeAlias alias="Person" type="iBatisTutorial.Model.Person, iBatisTutorial.Model" />
+ </alias>
+
+ <resultMaps>
+ <resultMap id="SelectResult" class="Person">
+ <result property="Id" column="PER_ID" />
+ <result property="FirstName" column="PER_FIRST_NAME" />
+ <result property="LastName" column="PER_LAST_NAME" />
+ <result property="BirthDate" column="PER_BIRTH_DATE" />
+ <result property="WeightInKilograms" column="PER_WEIGHT_KG" />
+ <result property="HeightInMeters" column="PER_HEIGHT_M" />
+ </resultMap>
+ </resultMaps>
+
+ <statements>
+
+ <select id="Select" parameterClass="int" resultMap="SelectResult">
+ select
+ PER_ID,
+ PER_FIRST_NAME,
+ PER_LAST_NAME,
+ PER_BIRTH_DATE,
+ PER_WEIGHT_KG,
+ PER_HEIGHT_M
+ from PERSON
+ <dynamic prepend="WHERE">
+ <isParameterPresent>
+ PER_ID = #value#
+ </isParameterPresent>
+ </dynamic>
+ </select>
+
+ <insert id="Insert" parameterClass="Person">
+ 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#)
+ </insert>
+
+ <update id="Update" parameterClass="Person">
+ 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#
+ </update>
+
+ <delete id="Delete" parameterClass="int">
+ delete from PERSON
+ where PER_ID = #value#
+ </delete>
+
+ </statements>
+</sqlMap></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 <isParameterPresent> tag in the
+ <select> element? The <isParameterPresent> 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> <asp:DataGrid id="dgList" Runat="server"
+ AutoGenerateColumns=False
+ DataKeyField="Id"
+ OnEditCommand="List_Edit"
+ OnCancelCommand="List_Cancel"
+ OnUpdateCommand="List_Update"
+ OnDeleteCommand="List_Delete">
+ <Columns>
+ <asp:BoundColumn DataField="FirstName" HeaderText="First"></asp:BoundColumn>
+ <asp:BoundColumn DataField="LastName" HeaderText="Last"></asp:BoundColumn>
+ <asp:BoundColumn DataField="HeightInMeters" HeaderText="Height"></asp:BoundColumn>
+ <asp:BoundColumn DataField="WeightInKilograms" HeaderText="Weight"></asp:BoundColumn>
+ <asp:EditCommandColumn ButtonType="PushButton" EditText="Edit" CancelText="Cancel" UpdateText="Save">
+ </asp:EditCommandColumn>
+ <asp:ButtonColumn ButtonType="PushButton" Text="Delete" CommandName="Delete">
+ </asp:ButtonColumn>
+ </Columns>
+ </asp:DataGrid>
+ <p><asp:Button ID="btnAdd" Runat="server"></asp:Button></p></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>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.
+
+
+
+