You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2013/06/10 17:13:06 UTC
svn commit: r1491490 -
/db/derby/code/trunk/java/engine/org/apache/derby/vti/XmlVTI.java
Author: rhillegas
Date: Mon Jun 10 15:13:05 2013
New Revision: 1491490
URL: http://svn.apache.org/r1491490
Log:
DERBY-6256: Commit derby-6256-02-aa-allowParentTags.diff, allowing XmlVTIs to inherit columns from outer xml elements in which the primary row element is nested.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/vti/XmlVTI.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/vti/XmlVTI.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/vti/XmlVTI.java?rev=1491490&r1=1491489&r2=1491490&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/vti/XmlVTI.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/vti/XmlVTI.java Mon Jun 10 15:13:05 2013
@@ -21,19 +21,25 @@ limitations under the License.
package org.apache.derby.vti;
-import java.io.*;
-import java.lang.reflect.*;
+import java.io.InputStream;
import java.net.URL;
-import java.sql.*;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
-import javax.xml.parsers.*;
-import org.w3c.dom.*;
+import java.util.ArrayList;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* <p>
* This is a VTI designed to read XML files which are structured like row sets.
- * This VTI takes the following arguments:
+ * One form of this VTI takes the following arguments. This form is useful when
+ * all of the columns in the row can be constructed from data nested INSIDE the row Element.
* </p>
*
* <ul>
@@ -43,7 +49,7 @@ import org.w3c.dom.*;
* </ul>
*
* <p>
- * Here is a sample declaration:
+ * Here is a sample declaration of this first form of the XmlVTI:
* </p>
*
* <pre>
@@ -76,6 +82,70 @@ import org.w3c.dom.*;
*
* select * from findbugs where bugCount != 0;
* </pre>
+ *
+ * <p>
+ * A second form of this VTI takes the following arguments. This form is useful when
+ * some of the columns in the row are "inherited" from outer elements inside which the
+ * row element nests:
+ * </p>
+ *
+ * <ul>
+ * <li>xmlResourceName - An URL identifying an xml resource.</li>
+ * <li>rowTag - The tag of the element which contains the row-structured content.</li>
+ * <li>parentTags - Attributes and elements (to be treated as columns) from outer elements in which the rowTag is nested.</li>
+ * <li>childTags - Attributes and elements (to be treated as columns) inside the row element.</li>
+ * </ul>
+ *
+ *
+ * <p>
+ * Here is a sample declaration of this second form of the XmlVTI. Using the second form
+ * involves declaring an ArrayList type and a factory method too:
+ * </p>
+ *
+ * <pre>
+ * create type ArrayList external name 'java.util.ArrayList' language java;
+ *
+ * create function asList( cell varchar( 32672 ) ... ) returns ArrayList
+ * language java parameter style derby no sql
+ * external name 'org.apache.derby.vti.XmlVTI.asList';
+ *
+ * create function optTrace
+ * (
+ * xmlResourceName varchar( 32672 ),
+ * rowTag varchar( 32672 ),
+ * parentTags ArrayList,
+ * childTags ArrayList
+ * )
+ * returns table
+ * (
+ * stmtID int,
+ * queryID int,
+ * complete boolean,
+ * summary varchar( 32672 ),
+ * type varchar( 50 ),
+ * estimatedCost double,
+ * estimatedRowCount int
+ * )
+ * language java parameter style derby_jdbc_result_set no sql
+ * external name 'org.apache.derby.vti.XmlVTI.xmlVTI';
+ *
+ * create view optTrace as
+ * select *
+ * from table
+ * (
+ * optTrace
+ * (
+ * 'file:///Users/me/derby/mainline/z.xml',
+ * 'planCost',
+ * asList( 'stmtID', 'queryID', 'complete' ),
+ * asList( 'summary', 'type', 'estimatedCost', 'estimatedRowCount' )
+ * )
+ * ) v
+ * ;
+ *
+ * select * from optTrace
+ * where stmtID = 6 and complete
+ * order by estimatedCost * </pre>
*/
public class XmlVTI extends StringColumnVTI
{
@@ -101,6 +171,13 @@ public class XmlVTI extends StringCo
private DocumentBuilder _builder;
private NodeList _rawRows;
+ //
+ // The first n column names are attribute/element tags from parent
+ // elements. The trailing column names are attribute/element tags from
+ // the row element or its children.
+ //
+ private int _firstChildTagIdx; // first attribute/element to be found in the row or below
+
///////////////////////////////////////////////////////////////////////////////////
//
// CONSTRUCTORS
@@ -113,24 +190,46 @@ public class XmlVTI extends StringCo
* element, and an array of attribute-names/element-tags underneath the row element
* </p>
*/
- public XmlVTI( String xmlResourceName, String rowTag, String... childTags )
+ public XmlVTI( String xmlResourceName, String rowTag, int firstChildTagIdx, String... columnTags )
{
- super( childTags );
+ super( columnTags );
_xmlResourceName = xmlResourceName;
_rowTag = rowTag;
+ _firstChildTagIdx = firstChildTagIdx;
}
///////////////////////////////////////////////////////////////////////////////////
//
- // ENTRY POINT (SQL FUNCTION)
+ // ENTRY POINTS (SQL FUNCTIONS)
//
///////////////////////////////////////////////////////////////////////////////////
- /** This is the static method bound to the function */
+ /** This is the static method for creating functions with only child tags */
public static XmlVTI xmlVTI( String xmlResourceName, String rowTag, String... childTags )
{
- return new XmlVTI( xmlResourceName, rowTag, childTags );
+ return new XmlVTI( xmlResourceName, rowTag, 0, childTags );
+ }
+
+ /** This is the static method for creating functions with both parent and child tags */
+ public static XmlVTI xmlVTI
+ ( String xmlResourceName, String rowTag, ArrayList<String> parentTags, ArrayList<String> childTags )
+ {
+ String[] allTags = new String[ parentTags.size() + childTags.size() ];
+ int idx = 0;
+ for ( String tag : parentTags ) { allTags[ idx++ ] = tag; }
+ for ( String tag : childTags ) { allTags[ idx++ ] = tag; }
+
+ return new XmlVTI( xmlResourceName, rowTag, parentTags.size(), allTags );
+ }
+
+ /** Factory method to create an ArrayList<String> */
+ public static ArrayList<String> asList( String... cells )
+ {
+ ArrayList<String> retval = new ArrayList<String>();
+ for ( String cell : cells ) { retval.add( cell ); }
+
+ return retval;
}
///////////////////////////////////////////////////////////////////////////////////
@@ -203,7 +302,7 @@ public class XmlVTI extends StringCo
* Fault in the list of rows.
* </p>
*/
- private void readRows() throws Exception
+ private void readRows() throws Exception
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -225,7 +324,7 @@ public class XmlVTI extends StringCo
* Parse a row into columns.
* </p>
*/
- private void parseRow( int rowNumber ) throws Exception
+ private void parseRow( int rowNumber ) throws Exception
{
Element rawRow = (Element) _rawRows.item( rowNumber );
int columnCount = getColumnCount();
@@ -234,35 +333,59 @@ public class XmlVTI extends StringCo
for ( int i = 0; i < columnCount; i++ )
{
- // first look for an attribute by the column name
- String columnName = getColumnName( i + 1 );
- String contents = rawRow.getAttribute( columnName );
-
- // if there is not attribute by that name, then look for descendent elements by
- // that name. concatenate them all.
- if ( (contents == null) || "".equals( contents ) )
+ _currentRow[ i ] = findColumnValue( rawRow, i );
+ }
+ }
+
+ /**
+ * <p>
+ * Find the value of a column inside an element. The columnNumber is 0-based.
+ * </p>
+ */
+ private String findColumnValue( Element rawRow, int columnNumber )
+ throws Exception
+ {
+ // handle tags which are supposed to come from outer elements
+ boolean inParent = (columnNumber < _firstChildTagIdx);
+ if ( inParent )
+ {
+ Node parent = rawRow.getParentNode();
+ if ( (parent == null ) || !( parent instanceof Element) ) { return null; }
+ else { rawRow = (Element) parent; }
+ }
+
+ // first look for an attribute by the column name
+ String columnName = getColumnName( columnNumber + 1 );
+ String contents = rawRow.getAttribute( columnName );
+
+ // missing attributes turn up as empty strings. make them null instead
+ if ( "".equals( contents ) ) { contents = null; }
+
+ // if there is not attribute by that name, then look for descendent elements by
+ // that name. concatenate them all.
+ if ( contents == null )
+ {
+ NodeList children = rawRow.getElementsByTagName( columnName );
+
+ if ( (children != null) && (children.getLength() > 0) )
{
- NodeList children = rawRow.getElementsByTagName( columnName );
+ int childCount = children.getLength();
+ StringBuilder buffer = new StringBuilder();
- if ( (children != null) && (children.getLength() > 0) )
+ for ( int j = 0; j < childCount; j++ )
{
- int childCount = children.getLength();
- StringBuffer buffer = new StringBuffer();
-
- for ( int j = 0; j < childCount; j++ )
- {
- Element child = (Element) children.item( j );
- // separate values with spaces.
- if (j != 0)
- buffer.append(" ");
- buffer.append( squeezeText( child ) );
- }
- contents = buffer.toString();
+ Element child = (Element) children.item( j );
+ // separate values with spaces.
+ if (j != 0){ buffer.append(" "); }
+ buffer.append( squeezeText( child ) );
}
+ contents = buffer.toString();
}
-
- _currentRow[ i ] = contents;
}
+
+ // recurse if looking in parent element
+ if ( inParent && (contents == null) ) { return findColumnValue( rawRow, columnNumber ); }
+ else { return contents; }
}
/**