franta-hg@206: * Prints machine-readable output – XML document containing resultsets and updates count. Good
franta-hg@155: * choice for further processing – e.g. XSL transformation.
franta-hg@155: *
franta-hg@206: *
franta-hg@206: * TODO: XSD
franta-hg@29: *
franta-hg@29: * @author Ing. František Kučera (frantovo.cz)
franta-hg@29: */
franta-hg@207: @PropertyDeclaration(name = XmlFormatter.PROPERTY_LABELED_COLUMNS, defaultValue = "false", type = Boolean.class, description = "whether to add 'label' attribute to each 'column' element")
franta-hg@128: public class XmlFormatter extends AbstractXmlFormatter {
franta-hg@29:
franta-hg@79: public static final String NAME = "xml"; // bash-completion:formatter
franta-hg@131: public static final String PROPERTY_LABELED_COLUMNS = "labeledColumns";
franta-hg@165: private static final Logger log = Logger.getLogger(XmlFormatter.class.getName());
franta-hg@131: private final boolean labeledColumns;
franta-hg@29:
franta-hg@29: public XmlFormatter(FormatterContext formatterContext) {
franta-hg@29: super(formatterContext);
franta-hg@131: labeledColumns = formatterContext.getProperties().getBoolean(PROPERTY_LABELED_COLUMNS, false);
franta-hg@29: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@128: public void writeStartBatch() {
franta-hg@128: super.writeStartBatch();
franta-hg@128: printStartDocument();
franta-hg@154: printStartElement(qname("batchResult"), singleAttribute(qname("xmlns"), Xmlns.BATCH_RESULT));
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@128: public void writeEndBatch() {
franta-hg@128: super.writeEndBatch();
franta-hg@128: printEndElement();
franta-hg@128: printEndDocument();
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@128: public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
franta-hg@128: super.writeStartDatabase(databaseDefinition);
franta-hg@128: Map attributes = databaseDefinition.getName() == null ? null : singleAttribute(qname("name"), databaseDefinition.getName());
franta-hg@128: printStartElement(qname("database"), attributes);
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@128: public void writeEndDatabase() {
franta-hg@128: super.writeEndDatabase();
franta-hg@128: printEndElement();
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@142: public void writeStartStatement() {
franta-hg@142: super.writeStartStatement();
franta-hg@142: printStartElement(qname("statement"));
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@142: public void writeEndStatement() {
franta-hg@142: super.writeEndStatement();
franta-hg@128: printEndElement();
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@128: public void writeQuery(String sql) {
franta-hg@128: super.writeQuery(sql);
franta-hg@128: printTextElement(qname("sql"), null, sql);
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@128: public void writeParameters(List extends Parameter> parameters) {
franta-hg@128: super.writeParameters(parameters);
franta-hg@128:
franta-hg@128: for (Parameter p : notNull(parameters)) {
franta-hg@128:
franta-hg@128: Map attributes = new LinkedHashMap<>(2);
franta-hg@128: if (p instanceof NamedParameter) {
franta-hg@128: attributes.put(qname("name"), ((NamedParameter) p).getName());
franta-hg@128: }
franta-hg@128: attributes.put(qname("type"), p.getType().name());
franta-hg@128:
franta-hg@128: printTextElement(qname("parameter"), attributes, String.valueOf(p.getValue()));
franta-hg@128: }
franta-hg@128:
franta-hg@128: }
franta-hg@128:
franta-hg@128: @Override
franta-hg@142: public void writeStartResultSet(ColumnsHeader header) {
franta-hg@142: super.writeStartResultSet(header);
franta-hg@142: printStartElement(qname("resultSet"));
franta-hg@128:
franta-hg@128: for (ColumnDescriptor cd : header.getColumnDescriptors()) {
franta-hg@128: Map attributes = new LinkedHashMap<>(4);
franta-hg@128: attributes.put(qname("label"), cd.getLabel());
franta-hg@128: attributes.put(qname("name"), cd.getName());
franta-hg@128: attributes.put(qname("typeName"), cd.getTypeName());
franta-hg@128: attributes.put(qname("type"), String.valueOf(cd.getType()));
franta-hg@128: printEmptyElement(qname("columnHeader"), attributes);
franta-hg@128: }
franta-hg@128: }
franta-hg@129:
franta-hg@129: @Override
franta-hg@142: public void writeEndResultSet() {
franta-hg@142: super.writeEndResultSet();
franta-hg@142: printEndElement();
franta-hg@142: }
franta-hg@142:
franta-hg@142: @Override
franta-hg@129: public void writeStartRow() {
franta-hg@129: super.writeStartRow();
franta-hg@129: printStartElement(qname("row"));
franta-hg@129: }
franta-hg@129:
franta-hg@129: @Override
franta-hg@129: public void writeColumnValue(Object value) {
franta-hg@129: super.writeColumnValue(value);
franta-hg@131:
franta-hg@131: Map attributes = null;
franta-hg@131: if (labeledColumns) {
franta-hg@151: attributes = new LinkedHashMap<>(2);
franta-hg@131: attributes.put(qname("label"), getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel());
franta-hg@131: }
franta-hg@131:
franta-hg@151: if (value == null) {
franta-hg@151: if (attributes == null) {
franta-hg@151: attributes = new LinkedHashMap<>(2);
franta-hg@151: }
franta-hg@163: attributes.put(qname("null"), "true");
franta-hg@163: printEmptyElement(qname("column"), attributes);
franta-hg@165: } else if (value instanceof Array) {
franta-hg@206:
franta-hg@165: Array sqlArray = (Array) value;
franta-hg@165: try {
franta-hg@165: Object[] array = (Object[]) sqlArray.getArray();
franta-hg@165: printStartElement(qname("column"), attributes);
franta-hg@165: printArray(array);
franta-hg@165: printEndElement();
franta-hg@165: } catch (SQLException e) {
franta-hg@233: // FIXME: rewrite array formatting, remember array mode, don't try sqlArray.getArray() again and again if it has failed
franta-hg@165: log.log(Level.SEVERE, "Unable to format array", e);
franta-hg@233: try {
franta-hg@233: ResultSet arrayResultSet = sqlArray.getResultSet();
franta-hg@233: //int columnCount = arrayResultSet.getMetaData().getColumnCount();
franta-hg@233: ArrayList