I am pretty new to BIRT and XML but trying to fix a performance issue. Right now we have a report that is using a big XML file as the data source and it is taking to long to load. So I've been exploring different options. I found that you can use a Scripted Data Source and use java to parse the XML.
My problem is that it is leaving some of rows blank even if there is information in the XML file.
I have a test XML file that looks like this:
<?xml version="1.0"?>
<library>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author name="Giada De Laurentiis" country="it"/>
<year>2005</year>
<info>asdfghjkl</info>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author name="J K. Rowling" country="uk" />
<year>2005</year>
<info>asdfghjkl</info>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author name="James McGovern" country="us" />
<author name="Per Bothner" country="us" />
<info>asdfghjkl</info>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author name="Erik T. Ray" country="us" />
<year>2003</year>
<info>asdfghjkl</info>
</book>
</library>
In my Data Set under open I have
importPackage(javax.xml.parsers);
importPackage(javax.xml.xpath);
importPackage(org.w3c.dom);
importPackage(org.xml.sax);
var factory = DocumentBuilderFactory.newInstance();
var builder = null;
doc = null;
var expr = null;
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
doc = builder.parse(params["FileName"].value);
doc.getDocumentElement().normalize();
// create an XPathFactory
var xFactory = XPathFactory.newInstance();
// create an XPath object
xpath = xFactory.newXPath();
// compile the XPath expression
expr = xpath.compile("/library/*");
// run the query and get a nodeset
var result = expr.evaluate(doc, XPathConstants.NODESET);
//initialize object variables to be used in the fetch method
nodes = result;
x = 0;
y = 0;
cnt = nodes.getLength();
Under fetch I have
var lboolAllowed = false;
if (x < cnt)
{
var nodeList = nodes.item(x).getChildNodes();
var nodeListLength = nodes.item(x).getChildNodes().getLength();
for(var i=0; i<nodeListLength; i++)
{
var nodeName = nodeList.item(i).getNodeName();
var nodeText = nodeList.item(i).getTextContent();
if(nodeName == "category")
{
row["category"] = nodeText;
}
if(nodeName == "year")
{
row["year"] = nodeText;
}
else if(nodeName == "info")
{
row["info"] = nodeText;
}
else if(nodeName == "title")
{
row["title"] = nodeText;
}
else if(nodeName == "author")
{
row["author"] = nodeText;
}
else if(nodeName == "country")
{
row["country"] = nodeText;
}
y++
}
x++;
y=0;
return (true);
}
return (false);
Then I have a Report Parameter called FileName that points to where the XML file is.
The rows that are coming up blank are category, author and country. I am using version 3.2.23.
Here is the XML Source from the report if that helps.
<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
<property name="createdBy">Eclipse BIRT Designer Version 4.6.0.v201606072122</property>
<property name="units">in</property>
<property name="iconFile">/templates/blank_report.gif</property>
<property name="bidiLayoutOrientation">ltr</property>
<property name="imageDPI">120</property>
<parameters>
<scalar-parameter name="FileName" id="11">
<property name="hidden">true</property>
<property name="valueType">static</property>
<property name="dataType">string</property>
<property name="distinct">true</property>
<simple-property-list name="defaultValue">
<value type="constant">C:\Users\1122335\Desktop\Workspace\test\new207.xml</value>
</simple-property-list>
<list-property name="selectionList"/>
<property name="paramType">simple</property>
<property name="controlType">text-box</property>
<structure name="format">
<property name="category">Unformatted</property>
</structure>
</scalar-parameter>
</parameters>
<data-sources>
<script-data-source name="Data Source" id="9"/>
</data-sources>
<data-sets>
<script-data-set name="Data Set" id="12">
<list-property name="resultSetHints">
<structure>
<property name="position">1</property>
<property name="name">year</property>
<property name="dataType">integer</property>
</structure>
<structure>
<property name="position">2</property>
<property name="name">info</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">3</property>
<property name="name">category</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">4</property>
<property name="name">title</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">5</property>
<property name="name">author</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">6</property>
<property name="name">country</property>
<property name="dataType">string</property>
</structure>
</list-property>
<list-property name="columnHints">
<structure>
<property name="columnName">year</property>
<text-property name="displayName">year</text-property>
</structure>
<structure>
<property name="columnName">info</property>
<text-property name="displayName">info</text-property>
</structure>
<structure>
<property name="columnName">category</property>
<text-property name="displayName">category</text-property>
</structure>
<structure>
<property name="columnName">title</property>
<text-property name="displayName">title</text-property>
</structure>
<structure>
<property name="columnName">author</property>
<text-property name="displayName">author</text-property>
</structure>
<structure>
<property name="columnName">country</property>
<text-property name="displayName">country</text-property>
</structure>
</list-property>
<structure name="cachedMetaData">
<list-property name="resultSet">
<structure>
<property name="position">1</property>
<property name="name">year</property>
<property name="dataType">integer</property>
</structure>
<structure>
<property name="position">2</property>
<property name="name">info</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">3</property>
<property name="name">category</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">4</property>
<property name="name">title</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">5</property>
<property name="name">author</property>
<property name="dataType">string</property>
</structure>
<structure>
<property name="position">6</property>
<property name="name">country</property>
<property name="dataType">string</property>
</structure>
</list-property>
</structure>
<property name="dataSource">Data Source</property>
<method name="open"><![CDATA[importPackage(javax.xml.parsers);
importPackage(javax.xml.xpath);
importPackage(org.w3c.dom);
importPackage(org.xml.sax);
var factory = DocumentBuilderFactory.newInstance();
var builder = null;
doc = null;
var expr = null;
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
//doc = builder.parse("C:\Users\1122335\Desktop\Workspace\test\new207.xml");
doc = builder.parse(params["FileName"].value);
doc.getDocumentElement().normalize();
// create an XPathFactory
var xFactory = XPathFactory.newInstance();
// create an XPath object
xpath = xFactory.newXPath();
// compile the XPath expression
expr = xpath.compile("/library/*");
// run the query and get a nodeset
var result = expr.evaluate(doc, XPathConstants.NODESET);
//initialize object variables to be used in the fetch method
nodes = result;
x = 0;
y = 0;
cnt = nodes.getLength();
]]></method>
<method name="fetch"><![CDATA[var lboolAllowed = false;
if (x < cnt)
{
var nodeList = nodes.item(x).getChildNodes();
var nodeListLength = nodes.item(x).getChildNodes().getLength();
for(var i=0; i<nodeListLength; i++)
{
var nodeName = nodeList.item(i).getNodeName();
var nodeText = nodeList.item(i).getTextContent();
if(nodeName == "#category")
{
row["category"] = nodeText;
}
if(nodeName == "year")
{
row["year"] = nodeText;
}
else if(nodeName == "info")
{
row["info"] = nodeText;
}
else if(nodeName == "//title")
{
row["title"] = nodeText;
}
else if(nodeName == "//author")
{
row["author"] = nodeText;
}
else if(nodeName == "//country")
{
row["country"] = nodeText;
}
y++
}
x++;
y=0;
return (true);
}
return (false);]]></method>
<method name="close"><![CDATA[factory = null;
builder = null;
doc = null;
expr = null;
builder = null;
xFactory = null;
// create an XPath object
xpath = null;
result = null;
//initialize object variables to be used in the fetch method
nodes = null;
x = 0;
y = 0;
cnt = null;]]></method>
</script-data-set>
</data-sets>
<page-setup>
<simple-master-page name="Simple MasterPage" id="2">
<page-footer>
<text id="3">
<property name="contentType">html</property>
<text-property name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-property>
</text>
</page-footer>
</simple-master-page>
</page-setup>
<body>
<table id="356">
<property name="dataSet">Data Set</property>
<list-property name="boundDataColumns">
<structure>
<property name="name">year</property>
<text-property name="displayName">year</text-property>
<expression name="expression" type="javascript">dataSetRow["year"]</expression>
<property name="dataType">integer</property>
</structure>
<structure>
<property name="name">info</property>
<text-property name="displayName">info</text-property>
<expression name="expression" type="javascript">dataSetRow["info"]</expression>
<property name="dataType">string</property>
</structure>
<structure>
<property name="name">category</property>
<text-property name="displayName">category</text-property>
<expression name="expression" type="javascript">dataSetRow["category"]</expression>
<property name="dataType">string</property>
</structure>
<structure>
<property name="name">title</property>
<text-property name="displayName">title</text-property>
<expression name="expression" type="javascript">dataSetRow["title"]</expression>
<property name="dataType">string</property>
</structure>
<structure>
<property name="name">author</property>
<text-property name="displayName">author</text-property>
<expression name="expression" type="javascript">dataSetRow["author"]</expression>
<property name="dataType">string</property>
</structure>
<structure>
<property name="name">country</property>
<text-property name="displayName">country</text-property>
<expression name="expression" type="javascript">dataSetRow["country"]</expression>
<property name="dataType">string</property>
</structure>
</list-property>
<column id="390"/>
<column id="391"/>
<column id="392"/>
<column id="393"/>
<column id="394"/>
<column id="395"/>
<header>
<row id="357">
<cell id="358">
<label id="359">
<text-property name="text">year</text-property>
</label>
</cell>
<cell id="360">
<label id="361">
<text-property name="text">info</text-property>
</label>
</cell>
<cell id="362">
<label id="363">
<text-property name="text">category</text-property>
</label>
</cell>
<cell id="364">
<label id="365">
<text-property name="text">title</text-property>
</label>
</cell>
<cell id="366">
<label id="367">
<text-property name="text">author</text-property>
</label>
</cell>
<cell id="368">
<label id="369">
<text-property name="text">country</text-property>
</label>
</cell>
</row>
</header>
<detail>
<row id="370">
<cell id="371">
<data id="372">
<property name="resultSetColumn">year</property>
</data>
</cell>
<cell id="373">
<data id="374">
<property name="resultSetColumn">info</property>
</data>
</cell>
<cell id="375">
<data id="376">
<property name="resultSetColumn">category</property>
</data>
</cell>
<cell id="377">
<data id="378">
<property name="resultSetColumn">title</property>
</data>
</cell>
<cell id="379">
<data id="380">
<property name="resultSetColumn">author</property>
</data>
</cell>
<cell id="381">
<data id="382">
<property name="resultSetColumn">country</property>
</data>
</cell>
</row>
</detail>
<footer>
<row id="383">
<cell id="384"/>
<cell id="385"/>
<cell id="386"/>
<cell id="387"/>
<cell id="388"/>
<cell id="389"/>
</row>
</footer>
</table>
</body>
</report>
This is an XML/DOM related issue: nodeName does not have # or // as prefix (that is XPath stuff) but just the element or attribute name, so not #category but just category, remove them in
if(nodeName == "#category")
and
else if(nodeName == "//author")
{
row["author"] = nodeText;
}
else if(nodeName == "//country")
{
row["country"] = nodeText;
}
The table in DOM Node javadoc shows what is returned by Node.getNodeName()
Additionally the nodes where you query category/author/country are wrong, see:
var book = nodes.item(x);
var nodeList = book.getChildNodes();
var nodeListLength = nodeList.getLength();
row["category"] = book.getAttribute("category");
for(int i=0; i<nodeListLength; i++)
{
var child = nodeList.item(i);
var nodeName = child.getNodeName();
var nodeText = child.getTextContent();
if(nodeName == "year")
{
row["year"] = nodeText);
}
else if(nodeName == "info")
{
row["info"] = nodeText);
}
else if(nodeName == "title")
{
row["title"] = nodeText);
}
else if(nodeName == "author")
{
row["author"] = child.getAttribute("name");
row["country"] = child.getAttribute("country");
}
Note: author is actually a list
Related
Is using two DAO at the same time impossible?
Error
private SqlSessionFactory factory = MyBatisconfig.getSqlSessionFactory();
getSqlSessionFactory(); <-- this is red line
Error
Syntax: The method getSqlSessionFactory() from the type MyBatisconfig refers to the missing type SqlSessionFactory
Here is the code I'm using :
public class MyBatisconfig {
private static SqlSessionFactory sqlSessionFactory;
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
String resource = "mybatis-config.xml";
Reader reader;
try {
reader = Resources.getResourceAsReader(resource);
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
return sqlSessionFactory;
}
}
AdminDAO.class
private SqlSessionFactory factory = MyBatisconfig.getSqlSessionFactory();
UserDAO.class
private SqlSessionFactory factory = MyBatisconfig.getSqlSessionFactory();
mybatis-config.xml
<configuration>
<properties resource="db.properties" />
<typeAliases>
<typeAlias type="human.vo.User" alias="user" />
<typeAlias type="human.vo.Admin" alias="admin" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/userMapper.xml" />
<mapper resource="mappers/adminMapper.xml" />
</mappers>
</configuration>
Two sqlSessionFactory <--- impossible??
I'm using spring batch to perform some calcul, in a reader I have to get a large data to be treated in a processor / writer, and this process takes a lot of (RAM).
So I tried to split the step using the partitioner like below :
<batch:step id="MyStep.master" >
<partition step="MyStep" partitioner="MyPartitioner">
<handler grid-size="1" task-executor="TaskExecutor" />
</partition>
</batch:step>
<batch:step id="MyStep" >
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk reader="MyReader" processor="MyProcessor"
writer="MyWriter" commit-interval="1000" skip-limit="1000">
<batch:skippable-exception-classes>
<batch:include class="...FunctionalException" />
</batch:skippable-exception-classes>
</batch:chunk>
</batch:tasklet>
</batch:step>
<bean id="MyPartitioner" class="...MyPartitioner" scope="step"/>
<bean id="TaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" >
<bean name="MyReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="dataSource" />
<property name="sql">
<value>
<![CDATA[
SELECT...
]]>
</value>
</property>
<property name="rowMapper" ref="MyRowMapper" />
</bean>
<bean id="MyRowMapper" class="...MyRowMapper" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="org.postgresql.Driver"/>
<property name="jdbcUrl" value="jdbc:postgresql://${database.host}/${database.name}"/>
<property name="user" value="${database.user}"/>
<property name="password" value="${database.password}"/>
<property name="acquireIncrement" value="1" />
<property name="autoCommitOnClose" value="true" />
<property name="minPoolSize" value="${min.pool.size}" /> <!-- min.pool.size=5 -->
<property name="maxPoolSize" value="${max.pool.size}" /> <!-- max.pool.size=15 -->
</bean>
But in vain the partitioning takes a lot of memory too, because the steps (slaves) are executed in parallel, what I want to do is to split the step and execute the thread successively (not in parallel) to reduce the memory usage (RAM), is that possible?
The question it's a bit old, so I'm not sure if this will be helpful now, probably you solved it yourself.
If you don't have a problem with the row execution order the solution would be to query your db in your partitioner bean, then pass to each partitions all the information to split in portions your table/s (start_key, end_key) this will reduce the ram usage (A LOT).
Some warnings:
Be aware that both the query used by partitioner bean and the reader must have the same "order by"
partitioned readers must be scope="step"
Don't use this method if you need to process the rows in a precise order
To tune the RAM try different combination of gridSize and taskExecutor maxCoreSize (that's why my gridSize is a jobParams)
Here an example:
XML Configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- JOB -->
<batch:job id="printPdf" job-repository="jobRepository"
restartable="false">
<batch:step id="MyStep">
<batch:partition step="MyStep.template"
partitioner="myPartitioner" handler="partitionHandler">
</batch:partition>
</batch:step>
</batch:job>
<!-- Partitioner -->
<bean id="myPartitioner" class="foo.MyPartitioner"
scope="step">
<property name="jdbcTemplate" ref="myJdbcTemplate" />
<property name="sql"
value="Select ...." />
<property name="rowMap">
<bean
class="foo.MyPartitionHandlerRowMapper" />
</property>
<property name="preparedStatementSetter">
<bean
class="org.springframework.batch.core.resource.ListPreparedStatementSetter">
<property name="parameters">
<list>
<value>#{jobParameters['param1']}</value>
</list>
</property>
</bean>
</property>
</bean>
<bean id="partitionHandler" scope="step"
class="org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler">
<property name="taskExecutor" ref="customTaskExecutor" />
<property name="gridSize" value="#{jobParameters['gridSize']}" />
<property name="step" ref="MyStep.template" />
</bean>
<bean id="customTaskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="8" />
<property name="maxPoolSize" value="8" />
<property name="waitForTasksToCompleteOnShutdown" value="true" />
<property name="awaitTerminationSeconds" value="120" />
</bean>
<batch:step id="MyStep.tempate">
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk commit-interval="2500" reader="myReader"
processor="myProcessor" writer="myWriter" skip-limit="2500">
<batch:skippable-exception-classes>
<batch:include class="...FunctionalException" />
</batch:skippable-exception-classes>
</batch:chunk>
</batch:tasklet>
</batch:step>
<!-- Beans -->
<!-- Processors -->
<bean id="myProcessor" class="foo.MyProcessor"
scope="step">
</bean>
<bean id="classLoaderVerifier"
class="it.addvalue.pkjwd.services.genbean.GenericStockKeysForNoDuplicate" />
<!-- Readers -->
<bean id="myReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader"
scope="step">
<property name="dataSource" ref="myDataSouce" />
<property name="sql"
value="select ... from ... where ID >= ? and ID <= ?" />
<property name="rowMapper">
<bean class="foo.MyReaderPartitionedRowMapper" />
</property>
<property name="preparedStatementSetter">
<bean
class="org.springframework.batch.core.resource.ListPreparedStatementSetter">
<property name="parameters">
<list>
<value>#{stepExecutionContext['START_ID']}</value>
<value>#{stepExecutionContext['END_ID']}</value>
</list>
</property>
</bean>
</property>
</bean>
<!-- Writers -->
<bean id="myWriter"
class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="assertUpdates" value="false" />
<property name="itemPreparedStatementSetter">
<bean class="foo.MyWriterStatementSetters" />
</property>
<property name="sql"
value="insert ..." />
<property name="dataSource" ref="myDataSouce" />
</bean>
</beans>
Your Partitioner Bean will look like this:
package foo;
import foo.model.MyTable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.batch.core.partition.support.Partitioner;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
public class MyPartitioner implements Partitioner
{
private JdbcTemplate jdbcTemplate;
private RowMapper<foo.model.MyTable> rowMap;
private String sql;
private PreparedStatementSetter preparedStatementSetter;
public JdbcTemplate getJdbcTemplate()
{
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate)
{
this.jdbcTemplate = jdbcTemplate;
}
public RowMapper<foo.model.MyTable> getRowMap()
{
return rowMap;
}
public void setRowMap(RowMapper<PkjwdPolizzePartition> rowMap)
{
this.rowMap = rowMap;
}
public String getSql()
{
return sql;
}
public void setSql(String sql)
{
this.sql = sql;
}
public PreparedStatementSetter getPreparedStatementSetter()
{
return preparedStatementSetter;
}
public void setPreparedStatementSetter(PreparedStatementSetter preparedStatementSetter)
{
this.preparedStatementSetter = preparedStatementSetter;
}
#Override
public Map<String, ExecutionContext> partition(int gridSize)
{
Map<String, ExecutionContext> map = new HashMap<String, ExecutionContext>();
try
{
List<PkjwdPolizzePartition> lstMyRows = jdbcTemplate.query(sql, preparedStatementSetter ,rowMap);
if ( lstMyRows.size() > 0 )
{
int total = lstMyRows.size();
int rowsPerPartition = total / gridSize;
int leftovers = total % gridSize;
total = lstMyRows.size() - 1;
int startPos = 0;
int endPos = rowsPerPartition - 1;
int i = 0;
while (endPos <= (total))
{
ExecutionContext context = new ExecutionContext();
if ( endPos + leftovers == total )
{
endPos = total;
}
else if ( endPos >= (total) )
{
endPos = total;
}
context.put("START_ID", lstMyRows.get(startPos).getId());
context.put("END_ID", lstMyRows.get(endPos).getId());
map.put("PART_" + StringUtils.leftPad("" + i, ("" + gridSize).length(), '0'), context);
i++;
startPos = endPos + 1;
endPos = endPos + rowsPerPartition;
}
}
}
catch ( Exception e )
{
e.printStackTrace();
}
return map;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<Root xmlns:tns="http://www.example.org/book" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/book test.xsd ">
<Class name="AirwayBill">
<Attribute name="billNo" primary="true" />
<Attribute name="date" primary="false" />
<Attribute name="shipper" primary="false" class="Person" />
</Class>
<Class name="Person">
<Attribute name="perId" primary="true" />
<Attribute name="fname" primary="false" />
<Attribute name="lname" primary="false" />
</Class>
</Root>
I want to read attribute value of attribute "name" of Tag in which attribute "class" is present.. how do i do that? i am using javax.xml.parsers.DocumentBuilder and javax.xml.parsers.DocumentBuilderFactory classes to parse and read the xml file.
Probably there is a better way to do it, but this works:
public static void parseXml(){
File fXmlFile = new File("c://test.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
try {
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList childList = root.getElementsByTagName("Class");
for (int i = 0; i<childList.getLength(); i++){
System.out.println("Class: " + childList.item(i).getAttributes().getNamedItem("name").getNodeValue());
NodeList attList = ((Element)childList.item(i)).getElementsByTagName("Attribute");
for (int j = 0; j<attList.getLength(); j++){
System.out.print(" Att: " + attList.item(j).getAttributes().getNamedItem("name").getNodeValue());
System.out.println(" primary " + attList.item(j).getAttributes().getNamedItem("primary").getNodeValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I'm trying to write a XML fragment containing a CData element in Spring StaxtItemWriter and Jaxb marshaller. But the output is either:
not wrap with <![CDATA[ ... ]]>
or escaped: < and > replaced by < and >
First, the item writer:
<bean id="userAuthorizationErrorItemWriter"
class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="rootTagName" value="UserAuthorizationEvent" />
<property name="rootElementAttributes">
<map>
<entry key="xmlns:xsi" value="http://www.w3.org/2001/XMLSchema-instance" />
</map>
</property>
<property name="marshaller" ref="userAuthorizationTypeMarshaller" />
<property name="overwriteOutput" value="true" />
<property name="resource" value="file://C:/TEMP/fichierOUT.xml" />
<property name="transactional" value="false" />
</bean>
Then the JAXB marshaller
<bean id="userAuthorizationTypeMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.usecase1.xsd.model"/>
</bean>
The java class (simplified):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "UserAuthorizationType", propOrder = {"action"})
#XmlRootElement(name = "UserAuthorization")
public class UserAuthorizationType {
#XmlElement(name = "Action", required = true)
protected String action;
public String getAction() {
return action;
}
public void setAction(String value) {
this.action = value;
}
}
When writing to file, I want that the Action value to be encapsulate into a <![CDATA[ ... ]]> block.
I tried using a #XmlJavaTypeAdapter(Adapter1.class) that return:
public String marshal(String value) {
return "<![CDATA[" + value + "]]>";
}
But the output is escaped:
<UserAuthorization><Action><![CDATA[first, second, third]]></Action></UserAuthorization>
Do you have any idea?
You will have to create a custom XML marshaller and register the elements that should be output as CDATA. See if this example helps https://jaxb.java.net/faq/JaxbCDATASample.java
I have a query which when i run in sqlDeveloper i get the result. Here is the query
select * from Losa_Cust_Reject_App rejectApp
inner join
Losa_Cust losaCust
on
rejectApp.app_Ref_No = losaCust.app_Ref_No
where
rejectApp.app_Ref_No != '0000001912' and rejectApp.app_Dt >= '23-SEP-2012'
and
rejectApp.cust_Id1 = 'A111111111' and rejectApp.cust_Id1_Type = '01';
i translated this query to hibernate as following
public List findAppByDate(String appRefNo, Date previousAppDate, String currentId1,
String currentIdType1) {
StringBuffer query = new StringBuffer("from ");
query.append(LosaCustRejectApp.class.getName());
query.append(" rejectApp inner join ");
query.append(LosaCust.class.getName());
query.append(" losaCust with rejectApp.appRefNo = losaCust.comp_id.appRefNo");
query.append(" where rejectApp.appRefNo != ? and rejectApp.appDt >= ?");
query.append(" and rejectApp.custId1 = ? and rejectApp.custId1Type = ? ");
List result = null;
try {
result = getHibernateTemplate().find(query.toString(),
new Object[] { appRefNo, previousAppDate, currentId1, currentIdType1 });
if (CollectionUtils.isNotEmpty(result)) {
return result;
}
} catch (Exception e) {
String message = e.getMessage();
System.out.println();
}
return result;
}
But i want to define mapping in hibernate so hibernate make the join automatically. How can i define association in hibernate file for the above query so hibernate make the join automatically.
here is my LosaCustReject.hbm.xml
<hibernate-mapping default-lazy="false">
<class name="com.thetasp.losa.data.LosaCustRejectApp" table="LOSA_CUST_REJECT_APP" optimistic-lock="version">
<id name="rejectAppId" type="java.lang.Long" column="REJECT_APP_ID">
<generator class="com.thetasp.code.runningno.HibernateId">
<param name="fieldCode">REJECT_APP_ID</param>
<param name="returnType">java.lang.Long</param>
</generator>
</id>
<version name="rowVersion" type="int" column="ROW_VERSION" access="property" unsaved-value="undefined" />
<property name="appRefNo" type="java.lang.String" column="APP_REF_NO" not-null="true" length="20" />
<property name="appDt" type="java.sql.Timestamp" column="APP_DT" not-null="true" length="23" />
<property name="custId1Type" type="java.lang.String" column="CUST_ID1_TYPE" not-null="true" length="1" />
<property name="custId1" type="java.lang.String" column="CUST_ID1" not-null="true" length="20" />
.......
<property name="updateDt" type="java.sql.Timestamp" column="UPDATE_DT" length="23" />
<!-- associations -->
</class>
</hibernate-mapping>
LosaCust.hbm.xml
<hibernate-mapping default-lazy="false">
<class name="com.thetasp.losa.data.LosaCust" table="LOSA_CUST" discriminator-value="I" optimistic-lock="version">
<composite-id name="comp_id" class="com.thetasp.losa.data.LosaCustPK">
<key-property name="custId" column="CUST_ID" type="java.lang.String" length="20" />
<key-property name="appRefNo" column="APP_REF_NO" type="java.lang.String" length="20" />
</composite-id>
<discriminator column="CUST_T" type="string" length="1" >
</discriminator>
<version name="rowVersion" type="int" column="ROW_VERSION" access="property" unsaved-value="undefined" />
<property name="custLevel" type="java.lang.String" column="CUST_LEVEL" not-null="false" length="10" />
.....
<property name="staySinceMth" type="java.lang.String" column="STAYED_SINCE_MTH" length="10" />
....
<subclass name="com.thetasp.losa.data.LosaIndvCust" discriminator-value="I" lazy="false" >
<property name="id1Type" type="java.lang.String" column="ID1_TYPE" length="1" />
<property name="id1" type="java.lang.String" column="ID1" length="20" />
....
</subclass>
</class>
Thanks
I think you could do something like this
In LosaCust.java define a field representing the one-to-many association to LosaCustRejectApp entities:
List<LosaCustRejectApp> associatedLosaCustRejectApps;
In LosaCust.hbm.xml you map this new field using something like this:
<list name="associatedLosaCustRejectApps" table="LOSA_CUST_REJECT_APP" >
<key>
<column name="app_Ref_No" not-null="true" />
</key>
<one-to-many class="com.thetasp.losa.data.LosaCustRejectApp" />
</set>
For more details and even a complete tutorial on how to do this type of mapping you can go here:
Hibernate – One-to-Many example (XML Mapping)
Best regards