DataTableContentProvider extends AbstractJrxmlContentProvider { @Override public Pair<InputStream, Boolean> prepareJrxmlAndReadInputParameters( InputStream jrxml, Map<String, Object> params, ProcessletInputs in, List<CodeType> processedIds, Map<String, String> parameters ) throws ProcessletException { boolean hasDatasourceInserted = false; for ( ProcessletInput input : in.getParameters() ) { if ( !processedIds.contains( input.getIdentifier() ) && input instanceof ComplexInput ) { ComplexInput complexIn = (ComplexInput) input; if ( SCHEMA.equals( complexIn.getSchema() ) && MIME_TYPE.equals( complexIn.getMimeType() ) ) { String tableId = complexIn.getIdentifier().getCode(); if ( tableId.equals( this.tableId ) ) { LOG.debug( "Found input parameter " + tableId + " representing a xml datasource!" ); ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { XMLAdapter jrxmlAdapter = new XMLAdapter( jrxml ); OMElement root = jrxmlAdapter.getRootElement(); String query = jrxmlAdapter.getNodeAsString( root, new XPath( "/jasper:jasperReport/jasper:queryString", nsContext ), "." ).trim(); XMLStreamReader tableAsStream = complexIn.getValueAsXMLStream(); Document document = XMLStreamUtils.getAsDocument( tableAsStream ); DOMXPath xpath = new DOMXPath( "tbl:Header/tbl:HeaderEntry" ); xpath.addNamespace( "tbl", SCHEMA ); int numberOfEntries = xpath.selectNodes( document.getDocumentElement() ).size(); if ( numberOfEntries > 1 ) { List<OMElement> fieldElements = jrxmlAdapter.getElements( root, new XPath( "/jasper:jasperReport/jasper:field", nsContext ) ); OMFactory factory = OMAbstractFactory.getOMFactory(); for ( OMElement fieldElement : fieldElements ) { String fieldName = fieldElement.getAttributeValue( new QName( "name" ) ); if ( isTableParameter( fieldName ) && tableId.equals( getIdentifierFromParameter( fieldName ) ) ) { OMElement textFieldElement = jrxmlAdapter.getElement( root, new XPath( ". + fieldName + "}']", nsContext ) ); for ( int i = 2; i < numberOfEntries + 1; i++ ) { OMElement newFieldElement = fieldElement.cloneOMElement(); String newFieldName = fieldName.substring( 0, fieldName.length() - 1 ) + i; newFieldElement.addAttribute( "name", newFieldName, null ); OMElement fieldDesc = jrxmlAdapter.getElement( newFieldElement, new XPath( "jasper:fieldDescription", nsContext ) ); String text = fieldDesc.getText(); text = text.replace( "[1]", "[" + i + "]" ); setText( factory, fieldDesc, text ); fieldElement.insertSiblingAfter( newFieldElement ); if ( textFieldElement != null ) { int width = jrxmlAdapter.getRequiredNodeAsInteger( textFieldElement, new XPath( "jasper:reportElement/@width", nsContext ) ); int x = jrxmlAdapter.getRequiredNodeAsInteger( textFieldElement, new XPath( "jasper:reportElement/@x", nsContext ) ); OMElement newDetailTextField = textFieldElement.cloneOMElement(); jrxmlAdapter.getElement( newDetailTextField, new XPath( "jasper:reportElement", nsContext ) ).addAttribute( "x", Integer.toString( x + width * ( i - 1 ) ), null ); OMElement newTextFieldExpr = jrxmlAdapter.getElement( newDetailTextField, new XPath( "jasper:textFieldExpression", nsContext ) ); setText( factory, newTextFieldExpr, "$F{" + newFieldName + "}" ); textFieldElement.insertSiblingAfter( newDetailTextField ); } } } } if ( LOG.isTraceEnabled() ) { LOG.trace( "Adjusted jrxml: " + root ); } } root.serialize( bos ); jrxml = new ByteArrayInputStream( bos.toByteArray() ); if ( parameters.containsKey( datasourceParameterName ) && "net.sf.jasperreports.engine.JRDataSource".equals( parameters.get( datasourceParameterName ) ) ) { InputStream is = getAsInputStream( complexIn.getValueAsXMLStream() ); params.put( datasourceParameterName, new JRXmlDataSource( is, query ) ); } else { Document doc = getAsDocument( complexIn.getValueAsXMLStream() ); params.put( datasourceParameterName, doc ); } hasDatasourceInserted = true; } catch ( Exception e ) { String msg = "Could not process data table content: " + e.getMessage(); LOG.error( msg, e ); throw new ProcessletException( msg ); } finally { IOUtils.closeQuietly( bos ); } processedIds.add( complexIn.getIdentifier() ); } } } } return new Pair<InputStream, Boolean>( jrxml, hasDatasourceInserted ); } DataTableContentProvider( Workspace workspace );  DataTableContentProvider( Workspace workspace, String datasourceParameterName ); @Override void inspectInputParametersFromJrxml( Map<String, ParameterDescription> parameterDescriptions,
                                                 List<JAXBElement<? extends ProcessletInputDefinition>> inputs,
                                                 XMLAdapter jrxmlAdapter, Map<String, String> parameters,
                                                 List<String> handledParameters ); @Override Pair<InputStream, Boolean> prepareJrxmlAndReadInputParameters( InputStream jrxml,
                                                                          Map<String, Object> params,
                                                                          ProcessletInputs in,
                                                                          List<CodeType> processedIds,
                                                                          Map<String, String> parameters ); static final String SCHEMA; final static String MIME_TYPE; }
@Test public void testPrepareJrxmlAndReadInputParameters() throws URISyntaxException, IOException, XMLStreamException, FactoryConfigurationError, ProcessletException { DataTableContentProvider tableContentProvider = getProvider(); List<CodeType> processedIds = new ArrayList<CodeType>(); Pair<InputStream, Boolean> jrxml = new Pair<InputStream, Boolean>( TestDataTableContentProviderTest.class.getResourceAsStream( "../templateWithTable.jrxml" ), false ); Map<String, Object> params = new HashMap<String, Object>(); ProcessletInputs in = Utils.getInputs( "REPORT", DataTableContentProvider.MIME_TYPE, DataTableContentProvider.SCHEMA, TestDataTableContentProviderTest.class.getResourceAsStream( "complexInputTABLE" ) ); tableContentProvider.setTableId( "REPORT" ); jrxml = tableContentProvider.prepareJrxmlAndReadInputParameters( jrxml.first, params, in, processedIds, new HashMap<String, String>() ); assertEquals( 1, params.size() ); assertEquals( 1, processedIds.size() ); XMLAdapter a = new XMLAdapter( jrxml.first ); String[] fieldNames = a.getNodesAsStrings( a.getRootElement(), new XPath( "/jasper:jasperReport/jasper:field/@name", nsContext ) ); List<String> detailFields = new ArrayList<String>(); List<String> headerFields = new ArrayList<String>(); for ( String field : fieldNames ) { if ( field.matches( TABLE_PREFIX + "[a-zA-Z0-9]*_(" + DETAIL_SUFFIX + ")[0-9]*" ) ) detailFields.add( field ); else if ( field.matches( TABLE_PREFIX + "[a-zA-Z0-9]*_(" + HEADER_SUFFIX + ")[0-9]*" ) ) headerFields.add( field ); } String[] textFieldNames = a.getNodesAsStrings( a.getRootElement(), new XPath( ". nsContext ) ); List<String> detailTextFields = new ArrayList<String>(); List<String> headerTextFields = new ArrayList<String>(); for ( String field : textFieldNames ) { if ( field.matches( "\\$F\\{" + TABLE_PREFIX + "[a-zA-Z0-9]*_(" + DETAIL_SUFFIX + ")[0-9]*\\}" ) ) detailTextFields.add( field ); else if ( field.matches( "\\$F\\{" + TABLE_PREFIX + "[a-zA-Z0-9]*_(" + HEADER_SUFFIX + ")[0-9]*\\}" ) ) headerTextFields.add( field ); } assertEquals( 4, detailFields.size() ); assertEquals( 4, headerFields.size() ); assertEquals( 4, detailTextFields.size() ); assertEquals( 4, headerTextFields.size() ); }