Using Castor to parse the following xml into POJOs using a mapping file is fairly straightforward:
<human name="bob"/>
<dog owner="alice"/>
It uses the name of the element to map to the class. But what if an attribute should be used to do the mapping? e.g.:
<animal type="human" name="bob"/>
<animal type="dog" owner="alice"/>
This contrived example is based on XML that I have to consume (tho I didn't author it!). Any ideas on how to approach this with Castor mapping files?
There are two ways to approach this. Change your Java class structure to have human and dog extend animal, and then write a mapping file for Animal.
Or just use XSLT to transform you data. Something like this might work:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="animal">
<xsl:text disable-output-escaping="yes"><![CDATA[<]]></xsl:text>
<xsl:value-of select="#type" /><xsl:text disable-output-escaping="yes"> </xsl:text>name="<xsl:value-of select="#name" />"
<xsl:text disable-output-escaping="yes"><![CDATA[/>]]></xsl:text>
</xsl:template>
</xsl:stylesheet>
Related
Let's say i have two xslt A, and B. In xslt A, we have a import/include statement to use some template from B. Is there a way in Java that we generate the resulting xslt (A merged with the imported template)?? Will it be possible??
SAXON has a way to export the compiled XSLT, but unfortunately the compiled XSLT has the link to the imported XSLT, which we don't want. Any input is appreciated.
Haven't explored XALAN yet on this one.
Why would you want to use Java for this, rather than XSLT?
Most of the job is easy, it can be done with a couple of template rules:
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="nested" on-no-match="shallow-copy"/>
<xsl:template match="xsl:stylesheet | xsl:transform" mode="nested">
<xsl:apply-templates mode="nested"/>
</xsl:template>
<xsl:template match="xsl:import | xsl:include" mode="#all">
<xsl:apply-templates select="document(#href)" mode="nested"/>
</xsl:template>
However, there are complications that make it difficult or impossible if certain XSLT features have been used, for example:
import precedences may not be converted correctly
xsl:apply-imports isn't going to work
attributes on xsl:stylesheet that have module scope (for example exclude-result-prefixes) will be lost.
I am given an xml file from an outside source (so I have no control over the attribute names) and unfortunately they use the same name for a paired set of data. I can't seem to figure out how to access the second value. An example of the data in the xml file is:
<?xml version="1.0"?>
<addressResponse>
<results>
<ownerName>Name1</ownerName>
<houseAddress>House1</houseAddress>
<houseAddress>CityState1</houseAddress>
<yearBuilt>Year1</yearBuilt>
</results>
<results>
<ownerName>Name2</ownerName>
<houseAddress>House2</houseAddress>
<houseAddress>CityState2</houseAddress>
<yearBuilt>Year2</yearBuilt>
</results>
</addressResponse>
I already have my java code together and can parse the xml but I need help handling the duplicate attribute name. I want my csv file to look like the following:
owner,address,citystate,yearbuilt
Name1,House1,CityState1,Year1
Name2,House2,CityState2,Year2
In my xsl file, I did the following "hoping" it would get the second houseAddress but it didn't:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">owner,address,citystate,yearbuilt
<xsl:for-each select="//results>
<xsl:value-of select="concat(ownerName,',',houseAddress,',',houseAddress,',',yearBuilt,'
')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
That gave me:
owner,address,citystate,yearbuilt
Name1,House1,House1,Year1
Name2,House2,House2,Year2
Is there a trick to do this? I can't get the attribute names changed from the originator so I'm stuck with them. Thank you in advance.
Use:
houseAddress[2]
to get the value of the second occurrence of the houseAddress element.
Note that we are assuming XSLT 1.0 here.
I want to create a word document from an HTML page.
I am planning to get the values on the HTML page and then pass these values to a document template.
I have used JSOUP to parse the contents of the HTML page and I get the values in my java program. I now want to pass these values to a word document template.
I want to know what are the best techniques I can use to create the document template and pass the values to the template to create the word document.
Thank You.
I found something very Interesting and simple. We just need to create a simple .xml template for the document we want to create and then programmatically change the contents of the xml file and save it as a ms word document.
You can find the xml template and the code here.
i suggest you use xslt, because your data is already in xml-format and there are well defined xml-formats from microsoft.
You could write a document template with word and save it in xml-format. Then you can convert the word-xml to a xsl-template with your html-xml as input. After the xslt-transformation you have a valid word-xml with your dynamic values from the html-xml.
XSLT example for excel
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="no" />
<xsl:template match="/">
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
...
<xsl:for-each
select="/yourroot/person">
...
<Cell ss:StyleID="uf">
<Data ss:Type="String">
<xsl:value-of
select="#Name" />
</Data>
</Cell>
..
</xsl:for-each>
...
</xsl:template>
</xsl:stylesheet>
JODReports and Docmosis might also be useful options for you since there is template populate and Doc output. If DOCX is your real target, then you can write out the document yourself since the XML is published - but that is a lot of work.
I am trying to transform an xsl + xml to xml (for later on transforming it into a pdf using FOP library). The JDK I am using is 1.5, and there is no way I can use another (that is what the company I work in is using). I read that the xalan jar of java 1.5 is the one responsible for the error. The text that causes the error is:
"dyn:evaluate($xpath)"/>
in:
<xsl:variable name="paramName" select="#name"/>
<xsl:variable name="xpath"
select="concat('/doc/data/',$paramName)" />
<fo:inline>
<xsl:value-of select="dyn:evaluate($xpath)"/>
</fo:inline>
</xsl:template>
is there a way arround it without changing the jar? Is there a way to write it differently? or am I using the wrong syntax?
Thanks for your help
evaluate() is an EXSLT extension function. It is non-standard, but many XSLT processors, including xalan, support it.
Have you declared the dyn namespace prefix in your stylesheet, so that it correctly references the EXSLT dynamic namespace?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn">
...
</xsl:stylesheet>
I am having an XML file
<?xml version="1.0" encoding="ISO-8859-1"?>
<Results>
<Row>
<COL1></COL1>
<COL2>25.00</COL2>
<COL3>2009-07-06 15:49:34.984</COL3>
<COL4>00001720</COL4>
</Row>
<Row>
<COL1>RJ</COL1>
<COL2>26.00</COL2>
<COL3>2009-07-06 16:04:16.156</COL3>
<COL4>00001729</COL4>
</Row>
<Row>
<COL1>SD</COL1>
<COL2>28.00</COL2>
<COL3>2009-07-06 16:05:04.375</COL3>
<COL4>00001721</COL4>
</Row>
</Results>
I have to convert this XML into CSV file. I have heard we can do such thing using XSLT. How can i do this in Java ( with/without XSLT )?
Using XSLT is often a bad idea. Use Apache Commons Digester. It's fairly easy to use - here's a rough idea::
Digester digester = new Digester();
digester.addObjectCreate("Results/Row", MyRowHolder.class);
digester.addCallMethod("Results/Row/COL1","addCol", 0);
// Similarly for COL2, etc.
digester.parse("mydata.xml");
This will create a MyRowHolder instance (where this is a class you provide). This class would have a addCol() method which would be called for each <COLn> with the contents of that tag.
In pseudo code:
loop through the rows:
loop through all children of `Row`:
write out the text
append a comma
new line
That quick little loop will write a comma at the end of each line, but I'm sure you can figure out how to remove that.
For actually parsing the XML, I suggest using JDOM. It has a pretty intuitive API.
In XSLT 1.0:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="ISO-8859-1" />
<xsl:template match="/Results">
<xsl:apply-templates select="Row" />
</xsl:template>
<xsl:template match="Row">
<xsl:apply-templates select="*" />
<xsl:if test="not(last())">
<xsl:value-of select="'
'" />
</xsl:if>
</xsl:template>
<xsl:template match="Row/*">
<xsl:value-of select="." />
<xsl:if test="not(last())">
<xsl:value-of select="','" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
If your COL* values can contain commas, you could wrap the values in double quotes:
<xsl:template match="Row/*">
<xsl:value-of select="concat('"', ., '"')" />
<!-- ... --->
If they can contain commas and double quotes, things could get a bit more complex due to the required escaping. You know your data, you'll be able to decide how to best format the output. Using a different separator (e.g. TAB or a pipe symbol) is also an option.
Read the XML file in.
Loop throught each record and add it to a csv file.
With XSLT you can use the JAXP interface to the XSLT processor and then use <xsl:text> in your stylesheet to convert to text output.
<xsl:text>
</xsl:text>
generates a newline. for example.
Use the straightforward SAX API via the standard Java JAXP package. This will allow you to write a class that receives events for each XML element your reader encounters.
Briefly:
read your XML in using SAX
record text values via the SAX DefaultHandler characters() method
when you get an end event for a COL, record this string value
when you get the ROW end event, simply write out a comma separated line of previously recorded values