JAXB bindings generic converter - binding

In JAXB binding i can change type of element from int to string and so on.
But i want not only data type conversion. I want replace integer Id's with they string equivalent.
This means that for every field i need write method.
Is anyway to get field name from parse method?
<!-- Resolve ID's -->
<jaxb:bindings node="/xs:schema/xs:element/xs:complexType/xs:sequence/xs:element[#name='Classification']/xs:complexType/xs:attribute[#name='id']">
<jaxb:property>
<jaxb:baseType>
<jaxb:javaType name="java.lang.String" parseMethod="com.company.lookup.Resolver.resolve" />
</jaxb:baseType>
</jaxb:property>
</jaxb:bindings>

Instead of defining the javaType on a per property basis you can override the Java type for an XML schema type in the global bindings section of the external binding document.
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings>
<jxb:globalBindings>
<jxb:javaType name="String" xmlType="xs:int"/>
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>

Related

XJC scope within XJB binding file

I got XJB binding file where I want to replace ALL dates with java.util.Date and I would like one specific element (with name 'MyElementName') to extend my custom class:
My XJB file:
<jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<!-- replace JAXBElement with real object where nillable="true" and minOccurs="0" -->
<jaxb:globalBindings generateElementProperty="false">
<!-- replace all dates with java.util.Date -->
<jaxb:javaType xmlType="xsd:dateTime" name="java.util.Date"
parseMethod="cz.i.sdp.nsessapi.util.DataTypeConverter.parseDateTime"
printMethod="cz.i.sdp.nsessapi.util.DataTypeConverter.printDateTime"/>
<jaxb:javaType xmlType="xsd:date" name="java.util.Date"
parseMethod="cz.i.sdp.nsessapi.util.DataTypeConverter.parseDateTime"
printMethod="cz.i.sdp.nsessapi.util.DataTypeConverter.printDateTime"/>
<jaxb:javaType xmlType="xsd:time" name="java.util.Date"
parseMethod="cz.i.sdp.nsessapi.util.DataTypeConverter.parseDateTime"
printMethod="cz.i.sdp.nsessapi.util.DataTypeConverter.printDateTime"/>
</jaxb:globalBindings>
<!-- Only element with name 'MyElementName' should extend
<jaxb:bindings schemaLocation="mySchema.xsd">
<jaxb:bindings node="//xs:element[#name='MyElementName']">
<xjc:superClass name="net.test.Whatever"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
The XJC enhancements will be silently ignored unless they are inside <globalBindings>. But then all generated classes will extend my custom class and I don't want that.
Is there a way to specify global bindings together with "scoped" bindings?
In here is mentioned "Global Scope", "Schema scope", "Definition Scope" and "Component scope" and they say "pecifically, declarations towards the top of the pyramid inherit and supersede declarations below them".

Ant xmlproperty task fails due to validation error

I want to extract an application version from a DITA map file. The ditamap file is valid and looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
<map id="user-manual">
<title><ph keyref="product"/> User Manual</title>
<topicmeta>
<prodinfo>
<prodname><keyword keyref="product"/></prodname>
<vrmlist>
<vrm version="4" release="3" modification="0"/>
</vrmlist>
</prodinfo>
</topicmeta>
<!--
[...]
-->
</map>
The information I want to get is in the <vrm> element.
"Easy peasy," I think to myself. So I use Ant's <xmlproperty> task to just load this XML file.
<project default="test">
<!-- notice #validate -->
<xmlproperty file="path/to/user-manual.ditamap" validate="false"/>
<target name="test">
<echo>${map.topicmeta.prodinfo.vrmlist.vrm(version)}</echo>
</target>
</project>
I don't want it to validate because Ant isn't going to find map.dtd.
Loading the file returns an error:
java.io.FileNotFoundException: /home/user/user-manual/map.dtd (No such file or directory)
If I remove the <!DOCTYPE> declaration or add a nested <xmlcatalog> with the path to the DTD, the file loads and I can use the properties from it.
I tested this with Ant 1.7.1 and 1.9.4. Is this a bug with Ant, or am I misunderstanding how Ant loads XML properties and the purpose of the validate attribute?
How can I make Ant obey my will?
I recommend to not use the <xmlproperty> for this. Please have a look at the docs:
For example, with semantic attribute processing enabled, this XML
property file:
<root>
<properties>
<foo location="bar"/>
<quux>${root.properties.foo}</quux>
</properties>
</root>
is roughly equivalent to the following fragments in a build.xml file:
<property name="root.properties.foo" location="bar"/>
<property name="root.properties.quux" value="${root.properties.foo}"/>
So the name of the properties you set is generated using their paths to the root element, so they rely on the structure of your DITA Map. But many elements in DITA may be set at different positions on your DITA Map. That means, if you move your metadata to another parent element, the property name changes and your build fails. This is probably not, what you want.
I'd recommend to grab those values via XSLT and than set the properties. That way, you could, for example, say, "give me the first occurance of that element with a simple //foo[1] XPath selector. Further on, you have the power of XSLT and XPath to slice values, format dates and so on before setting a property.
Update
You can use the oops consultancy Ant xmltask for that. It is very easy to set a property using <copy>:
<copy path="//critdates/created/#date"
property="document.date"
append="false"/>

Parse HTML stored as string in Database in ColdFusion

I have taken over this ColdFusion project and found that I need a value out of a database field that includes HTML. The field data looks like this (without the new lines):
<wddxPacket version="1.0">
<header />
<data>
<struct>
<var name="en">
<string>3 Nights' Lodging</string>
</var>
<var name="sp">
<string>3 Noches alojamiento</string>
</var>
</struct>
</data>
</wddxPacket>
I am wanting to use this data but I only need the text between the:
<var name='en'><string>3 Nights' Lodging</string></var>
I used a function that ColdFusion has to remove HTML:
#REReplaceNoCase(pkg.title, "<[^><]*>", '', 'ALL')#
But when I use that, I get something like this:
3 Nights' Lodging3 Noches alojamiento
All I want is:
3 Nights' Lodging
Examining the beginning of the string, ie <wddxPacket ...> it is actually WDDX.
If you do a search for ColdFusion + WDDX you will find the documentation for CFWDDX. It is a built in tag which supports conversions of WDDX strings to CFML objects (and vice versa) for easier manipulation. In your case use action="wddx2cfml" to convert the string back into a CF structure.
<cfwddx action="wddx2cfml" input="#text#" output="result">
<cfdump var="#result#" label="Raw object">
Then use the key #result.en# to grab the string you want.

parseKml() error

I have noticed that parseKml() function does not parse KML file correctly. For example, if you have this bit of KML:
<ExtendedData>
<Data name="Offer">
<value>Apples</value>
<value>Potatoes</value>
<value>Tomatoes</value>
</Data>
</ExtendedData>
The parseKml() function will return a kmlObject that will contain only the last value, i.e. "Tomatoes":
Does anyone have a solution for this?
The structure for the type of extended data you are using is for name/value pairs. i.e. a single name with a single value.
<ExtendedData>
<Data name="string">
<displayName>...</displayName> <!-- string -->
<value>...</value> <!-- string -->
</Data>
</ExtendedData>
So what you are trying will not work. If you wish to add an arbitrary XML Data structure to a KML Feature then you would do it like this.
<ExtendedData xmlns:offer="http://yourserver.com/namespace">
<offer:item>Apples</offer:item>
<offer:item>Potatoes</offer:item>
<offer:item>Tomatoes</offer:item>
</ExtendedData>
Based on the data structure, the 'offer' XML Schema file (http://yourserver.com/namespace) would be something like.
<?xml version="1.0" encoding="utf-16"?>
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="item" type="xsd:string" />
</xsd:schema>
I believe the <Data> element can only contain a single <value> - according to the docs, the "<Data> element allows you to add untyped name/value pairs to the user data associated with a given Feature."
So in your case, it's picking up the last <value> element only. You might find another way to add your custom data here: https://developers.google.com/kml/documentation/extendeddata

Is it possible to pass a string containing xml as input to the ant xslt task?

Trying to find out if it's possible to pass a string containing xml as input to the ant xslt task. Thanks!
The short answer is 'no'. But the slightly longer answer is: you can achieve the same by other means.
In one mode, the Ant xslt task will style the file specified by the in attribute, storing the result in the file specified by the out attribute.
<xslt in="src.xml" out="dest.xml" ...>
...
</xslt>
So, if you have the XML you want to process stored in an Ant property, you can write that out to 'src.xml' and have it processed by xslt. You can write the property ${xml}(the string) out to a file using something like:
<property name="xml"><![CDATA[
<myxml>
...
</myxml>]]>
</property>
<echo file="src.xml" message="${xml}" />
Alternatively you might use the echoxml task:
<echoxml file="src.xml">
<myxml>
...
</myxml>
</echoxml>
Which method you use will depend on the origin of the 'string'; whether it is raw text, or well-formed XML.
<xslt ...>
<style>
<string>
<![CDATA[
<xsl:stylesheet ...>
... rest of xslt ...
</xsl:stylesheet>
]]>
</string>
</style></xslt>

Resources