JAXB Parsing an XML file with variables (e.g. $(var1) ) - java

I'm interested to parse an XML that contains variables (which are defined by me inside the XML).
Here's an example of the XML files:
<parameters>
<parameter name="parent-id" value="1" />
<parameter name="child-id" value="1" />
</parameters>
<Parents>
<Parent id="$(parent-id)">
<Children>
<Child id="$(child-id)">
</Child>
</Children>
</Parent>
</Parents>
Is there a utility or some standard way to do so in Java? (using JAXB possibly)
Or should I implement this "mini" parsing mechanism by myself?
(A mechanism that identifies the variables and plants them inside the XML, and only later calls JAXB flows)
Thanks a lot in advance!

Use an XSLT transformation to convert your XML into an XSLT stylesheet and then execute the XSLT stylesheet. It's simple enough to convert
<parameters>
<parameter name="parent-id" value="1" />
<parameter name="child-id" value="1" />
</parameters>
into
<xsl:param name="parent-id" select="1" />
<xsl:param name="child-id" select="1" />
and
<Parent id="$(parent-id)">
into
<Parent id="{$parent-id}">
and to add a wrapper xsl:stylesheet and xsl:template element, and then you're done.

Related

Fetch an XML node-name as regex in XSL Stylesheet transformation

I have an XML (I know it is incorrect as per XML standards but I am restricted to changes as I am processing response from external party) as follows,
XML Snippet : <root>
<3party>some_value</3party>
</root>
I would like to fetch <3party> from above snippet in XSL stylesheet transformation. The fact is the <3party> element is invalid so I can no refer it as follows as it fails the xsl compilation. I would need a way to refer it as a partial element may be using some regx way? Following is incorrect.
<xsl:variable select="$response/root/3party" />
Any answers would help me out.
Edit : Possible solution to above usecase would be.
<xsl:for-each select="$response/root">
<!-- Node name -->
<xsl:variable name="name" select="local-name()" />
<!-- check if it contains party -->
<xsl:if test="contains($name, 'party')">
<!-- Node value -->
<xsl:variable name="value" select="node()" />
</xsl:if>
</xsl:for-each>
With regard to the code added to your question:
<xsl:for-each select="$response/root">
<!-- Node name -->
<xsl:variable name="name" select="local-name()" />
<!-- check if it contains party -->
<xsl:if test="contains($name, 'party')">
<!-- Node value -->
<xsl:variable name="value" select="node()" />
</xsl:if>
</xsl:for-each>
The test contains($name, 'party') will never return true. The context node's name is root and "root" does not contain "party".
On a more general note: you seem to think that the problem is how to get your XSLT stylesheet to compile. That is not so. The real problem here is that your input is not well-formed XML. The input must be parsed before it can be transformed, and if it's not well-formed XML, the process will fail well before even considering your stylesheet.

Parsing XML with structured element names

I've got some third party XML to parse in the following form. The number of tests is unbounded, but always an integer.
<tests>
<test_1>
<foo bar="baz" />
</test_1>
<test_2>
<foo bar="baz" />
</test_2>
<test_3>
<foo bar="baz" />
</test_3>
</tests>
I'm currently parsing this with XPath, but it's a lot of messing around. Is there any way of expressing this style of XML in a XSD schema and generating JAXB classes from it.
As far as I can see this is impossible, the only thing possible is the <xs:any processContents="lax"/> technique from
how can I define an xsd file that allows unknown (wildcard) elements?
, however this allows any content, not specifically <test_<integer>. I just want to confirm I'm not missing some XSD/JAXB trick?
Note I would have preferred the XML to be structured like this. I may try to convince the third-party to change.
<tests>
<test id="1">
<foo bar="baz" />
</test>
<test id="2">
<foo bar="baz" />
</test>
<test id="3">
<foo bar="baz" />
</test>
</tests>
While there are ways of dealing with elements with structured names such as numeric suffixes,
XPath: Use string tests against name() or local-name()
XSD: See XSD element name pattern matching
JAXB: See Dealing with poorly designed XML with JAXB
you really should fix the underlying XML design (test_1 should be test) instead.
For completeness here is full working example of using XSLT to transform the <test_N> input into <test id="N"> style
<tests>
<test_1>
<foo bar="baz" />
</test_1>
<test_2>
<foo bar="baz" />
</test_2>
<test_1234>
<foo bar="baz" />
</test_1234>
<other>
<foo></foo>
</other>
</tests>
XSL
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[substring(name(), 1, 5) = 'test_']">
<xsl:element name="test">
<xsl:attribute name="id"><xsl:value-of select="substring(name(), 6, string-length(name()) - 5)" /></xsl:attribute>
<xsl:copy-of select="node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Code
File input = new File("test.xml");
File stylesheet = new File("test.xsl");
StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
StringWriter writer = new StringWriter();
transformer.transform(new StreamSource(input), new StreamResult(writer));
System.out.println(writer);
Output
<?xml version="1.0" encoding="UTF-8"?>
<tests>
<test id="1">
<foo bar="baz"/>
</test>
<test id="2">
<foo bar="baz"/>
</test>
<test id="1234">
<foo bar="baz"/>
</test>
<other>
<foo/>
</other>
</tests>

Parsing xml with many attributes using Java JAXB

I have following xml which I am trying to parse using JAXB.
<?xml version="1.0" encoding="UTF-8"?>
<DataSet Name="core_donor" Version="2-0" SchemaVersion="1-0" SchemaDate="2014-01-16">
<DataPoints>
<DataPoint Name="donor_id" Value="105272" />
<DataPoint Name="surname" Value="TWO" />
<DataPoint Name="forename" Value="SCENARIO" />
<DataSubSet Name="blood_gas">
<DataPoints>
<DataPoint Name="blood_gas_no" Value="1" />
<DataPoint Name="blood_gas_date" Value="07/10/2014 10:15" />
</DataPoints>
<DataPoints>
<DataPoint Name="blood_gas_no" Value="2" />
<DataPoint Name="blood_gas_date" Value="07/10/2014 11:20" />
</DataPoints>
</DataSubSet>
<DataSubSet Name="liver_function">
<DataPoints>
<DataPoint Name="liver_function_no" Value="1" />
<DataPoint Name="liver_function_sample_date" Value="07/10/2014 11:10" />
</DataPoints>
<DataPoints>
<DataPoint Name="liver_function_no" Value="2" />
<DataPoint Name="liver_function_sample_date" Value="07/10/2014 13:52" />
</DataPoints>
</DataSubSet>
</DataPoints>
</DataSet>
I would be thankful if someone could point me how to achieve the parsing in java using JAXB.
Thanks!
For starters follow the below example
http://www.mkyong.com/java/jaxb-hello-world-example/
But DataPoints will be your RootElement , if am not wrong also refererence
check some examples for DOM parsing to traverse over the child nodes and read them.

How to set the output file name in Alfresco?

I was creating custom content model
in datalistModel.xml
<type name="dl:car">
<title>Car List</title>
<parent>dl:dataListItem</parent>
<properties>
<property name="dl:carName">
<title>Car Name</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
<property name="dl:carCompany">
<title>Company Name</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
</properties>
</type>
in share-datalist-form-config.xml
<!-- dl:contact type create car form -->
<config evaluator="model-type" condition="dl:car">
<forms>
<!-- Create item form -->
<form>
<field-visibility>
<!-- dl:contact type -->
<show id="dl:carName" />
<show id="dl:carCompany" />
</field-visibility>
<create-form template="../data-lists/forms/dataitem.ftl" />
</form>
</forms>
</config>
When I create a new car content in repository browser(I later configured menu to add content type 'Car'), the file name is 91b65385-86c6-4923-859d-6ecb3326319c.
<create-content>
<content id="plain-text" mimetype="text/plain" label="create-content.text" itemid="cm:content" icon="text"/>
<content id="html" mimetype="text/html" label="create-content.html" itemid="cm:content"/>
<content id="xml" mimetype="text/xml" label="create-content.xml" itemid="cm:content"/>
<content id="car" mimetype="text/xml" icon="xml" label="create-content.car" itemid="dl:car"/>
</create-content>
How can I make the file name to carName instead of 91b65385-86c6-4923-859d-6ecb3326319c
Any kind help is appreciated.
Take a look at the default 'share-datalist-form-config.xml'
You will see that almost every type specify <show id="cm:title" />
You could also just put <show id="name" /> or <show id="cm:name" /> to show the name attribute.
In order to put the title you will need to put the cm:titled aspect in your model.
Just check the 'datalistModel.xml' how the defaults are defined
And check this blog post to know a bit more how to create custom datalists.

Using XSLT to output multiple files

I'm trying to get an example that I found for using XSLT 2.0 to output multiple files working.
Using Saxon B 9.7.0.1 with Java 1.6, I get this error:
C:\Documents and Settings\Administrator\Desktop\saxon>java -jar saxon9.jar -s:input.xml -xsl:transform.xml
Error on line 15 of transform.xml:
java.net.URISyntaxException: Illegal character in path at index 20: file:///C:/Documents
and Settings/Administrator/Desktop/saxon/output1/test1.html
at xsl:for-each (file:/C:/Documents%20and%20Settings/Administrator/Desktop/saxon/transform.xml#10)
processing /tests/testrun[1]
Transformation failed: Run-time errors were reported
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<tests>
<testrun run="test1">
<test name="foo" pass="true" />
<test name="bar" pass="true" />
<test name="baz" pass="true" />
</testrun>
<testrun run="test2">
<test name="foo" pass="true" />
<test name="bar" pass="false" />
<test name="baz" pass="false" />
</testrun>
<testrun run="test3">
<test name="foo" pass="false" />
<test name="bar" pass="true" />
<test name="baz" pass="false" />
</testrun>
</tests>
transform.xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:output method="html" indent="yes" name="html"/>
<xsl:template match="/">
<xsl:for-each select="//testrun">
<xsl:variable name="filename"
select="concat('output1/',#run,'.html')" />
<xsl:value-of select="$filename" /> <!-- Creating -->
<xsl:result-document href="{$filename}" format="html">
<html><body>
<xsl:value-of select="#run"/>
</body></html>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Character 20 in your URI is the first space in "Documents and Settings". As a quick fix, try moving the files to a path without spaces. (Say, "C:\test" or some such.) I suspect the long-term fix is to change your XSLT to encode spaces to %20 before feeding $filename to xsl:result-document, but I'm afraid my XSLT-2.0-fu isn't strong enough to tell you how.
Edit: I haven't tested this, as I don't have an XSLT 2.0 processor handy, but after glancing at the docs, it looks like you want the encode-for-uri function. Something like the following may work for you:
<xsl:result-document href="{fn:encode-for-uri($filename)}" format="html">
I had the same issue with saxon -o: outputfile replacing the spaces with %20..
found out the issue is saxon and java versions.
Linux JAVA 1.7.0_45 : Saxon creates %20
Unix JAVA 1.5.0_61 : SAXON creates %20
Unix JAVA 1.4.2_22 : SAXON Does Not creates %20 directory

Categories

Resources