code: private String _serializeQuery(Query query, Map<Object, String> done, String id) throws ConverterException {
  
  	/*
  	 * <QUERY ID="1"> <COLUMNNAMES> <COLUMN NAME="a"></COLUMN> <COLUMN NAME="b"></COLUMN> </COLUMNNAMES>
  	 * 
  	 * <ROWS> <ROW> <COLUMN TYPE="STRING">a1</COLUMN> <COLUMN TYPE="STRING">b1</COLUMN> </ROW> <ROW>
  	 * <COLUMN TYPE="STRING">a2</COLUMN> <COLUMN TYPE="STRING">b2</COLUMN> </ROW> </ROWS> </QUERY>
  	 */
  	Collection.Key[] keys = CollectionUtil.keys(query);
  	StringBuilder sb = new StringBuilder(goIn() + "<QUERY ID=\"" + id + "\">");
  
  	// columns
  	sb.append(goIn() + "<COLUMNNAMES>");
  	for (int i = 0; i < keys.length; i++) {
  	    sb.append(goIn() + "<COLUMN NAME=\"" + keys[i].getString() + "\"></COLUMN>");
  	}
  	sb.append(goIn() + "</COLUMNNAMES>");
  
  	String value;
  	deep++;
  	sb.append(goIn() + "<ROWS>");
  	int len = query.getRecordcount();
  	for (int row = 1; row <= len; row++) {
  	    sb.append(goIn() + "<ROW>");
  	    for (int col = 0; col < keys.length; col++) {
  		try {
  		    value = _serialize(query.getAt(keys[col], row), done);
  		}
  		catch (PageException e) {
  		    value = _serialize(e.getMessage(), done);
  		}
  		sb.append("<COLUMN TYPE=\"" + type + "\">" + value + "</COLUMN>");
  	    }
  	    sb.append(goIn() + "</ROW>");
  
  	}
  	sb.append(goIn() + "</ROWS>");
  	deep--;
  
  	sb.append(goIn() + "</QUERY>");
  	type = "QUERY";
  	return sb.toString();
      }
docs: serialize a Query
  
  @param query Query to serialize
  @param done
  @return serialized query
  @throws ConverterException