百度空间 | 百度首页 
 
查看文章
 
Parsing and Processing Large XML Documents with Digester Rules(2)
2009年06月16日 星期二 12:14

Implementing Custom Rules

Download the complete source code for DBUnitRuleSet and DBUnitFlatRuleSet, with an accompanying Maven project. Below is the implementation of the following rules from DBUnitRuleSet: TableRule, TableColumnRule, TableRowRule, and TableRowValueRule. For convenience, the concrete rules could be coded as static inner classes within RuleSet.

Each rule may handle any combination of:

  • Opening the XML element using begin().
  • Closing the XML element using end().
  • Accessing the textual body of the selected XML element using body().

In this example, TableRule creates a child copy of the parent context for each new table, initializes the TABLE_NAME attribute, and creates a new TABLE_COLUMNS List for column names when handling the open <table> element. It also drops the current child context from the Digester stack at the closing </table> element.

private static class TableRule extends Rule {
 
  public void begin( String ns, String name, 
        Attributes att) {
     Map parentCtx = (Map) getDigester().peek();
     Map ctx = new HashMap(parentCtx);
     ctx.put("TABLE_NAME", att.getValue("name"));
     ctx.put("TABLE_COLUMNS", new ArrayList());
     ctx.put("TABLE_ROWS", new ArrayList());
     getDigester().push( ctx);
  }
 
  public void end( String ns, String name) {
     getDigester().pop();
  }
}

TableColumnRule adds a single column name into the TABLE_COLUMNS List in the current context.

private static class TableColumnRule 
      extends Rule {
  public void body( String ns, String name, 
        String text) {
     Map ctx = ( Map) getDigester().peek();
     ((List) ctx.get("TABLE_COLUMNS")).add(text);
  }
}

TableRowRule initializes a TABLE_ROW List that will be used to store values for the current table row at the opening <row> element.

This rule also executes SQL to insert data from the current row when the closing </row> element is handled. This way, the entire XML document is never loaded into memory. The actual SQL is constructed in the getStatement() method.

private static class TableRowRule extends Rule {
  public void begin( String ns, String name, 
        Attributes att) {
     Map ctx = (Map) getDigester().peek();
     ctx.put("TABLE_ROW", new ArrayList());
  }
 
  public void end( String ns, String name) 
        throws SQLException {
     Map ctx = (Map) getDigester().peek();
     execute(ctx, getStatement(ctx));
     ctx.remove("TABLE_ROW");
  }
  
  private int execute( Map ctx, 
      PreparedStatement st) throws SQLException {
     List values = (List) ctx.get("TABLE_ROW");
     if( values.size()==0) return 0;
 
     for( int i = 0; i<values.size(); i++) {
       st.setObject(i+1, values.get(i));
     }
     return st.executeUpdate();
  }
 
  private PreparedStatement getStatement( Map ctx) 
        throws SQLException {
     List cols = (List) ctx.get("TABLE_COLUMNS");
     if(cols.size()==0) return null;
 
     String tableName = getTableName(ctx);
     StringBuffer sql = new StringBuffer()
         .append("INSERT INTO ")
         .append(tableName).append("(");     
    StringBuffer values = new StringBuffer("?");
     sql.append(columns.get(0));
     for( int i = 1; i<columns.size(); i++) {
       sql.append(",").append(columns.get(i));
       values.append(",?");
     }
     sql.append(") VALUES (")
        .append(values).append(")");
 
     Connection conn = getConnection(ctx);
     return conn.prepareStatement(sql.toString());
  }
 
  private Connection getConnection( Map ctx) {
     return (Connection) ctx.get("CONNECTION");
  }
 
  private String getTableName(Map ctx) {
     return (String) ctx.get("TABLE_NAME");
  }
}

TableRowValueRule collects column values for the current row from the <value> element within the TABLE_ROW List of the current context.

private static class TableRowValueRule 
      extends Rule {
  public void body( String ns, String name, 
      String text) {
     Map ctx = (Map) getDigester().peek();
     ((List) ctx.get("TABLE_ROW")).add(text);
  }
}

The code above does not cache the created PreparedStatement instances, and instead recreates them every time. This may cause some performance concerns; however, if this code is used inside of a J2EE container, a connection is obtained from the container-managed DataSource, so most likely, caching of prepared statements is being done automatically. If not, then the getStatement() method can be extended in order to save created instances of the PreparedStatement within the processing context. Also, please note that these statements must be explicitly closed at the end of processing, such as in the end() method of TableRule.


类别:java学习 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu