How to define Hashmap in an XSD? - java

I am trying to make an xsd file out of a json response that I have got and later using that xsd to generate JAXB classes. My problem is that the json is in a format I am unable to convert to xsd. Here is my json :
{
"result1":[{"010201":[3,2,0,4,3,4]},{"010202":[1,6,3,2,2,2]},{"010203":[2,3,3,4,4,0]}],
"result2":[1,6,3,2,2,2],
"result3":[{"010201":[3,2,0,3,4]},{"010202":[1,6,3,2,2]},{"010203":[2,3,4,4,0]}],
"result4":[1,4,6,4,1],
"result5":[{"010201":34},{"010202":12},{"010203":78}],
"result6":41
}
Here is the above json in xml format :
<?xml version="1.0" encoding="UTF-8" ?>
<result1>
<010201>3</010201>
<010201>2</010201>
<010201>0</010201>
<010201>4</010201>
<010201>3</010201>
<010201>4</010201>
</result1>
<result1>
<010202>1</010202>
<010202>6</010202>
<010202>3</010202>
<010202>2</010202>
<010202>2</010202>
<010202>2</010202>
</result1>
<result1>
<010203>2</010203>
<010203>3</010203>
<010203>3</010203>
<010203>4</010203>
<010203>4</010203>
<010203>0</010203>
</result1>
<result2>1</result2>
<result2>6</result2>
<result2>3</result2>
<result2>2</result2>
<result2>2</result2>
<result2>2</result2>
<result3>
<010201>3</010201>
<010201>2</010201>
<010201>0</010201>
<010201>3</010201>
<010201>4</010201>
</result3>
<result3>
<010202>1</010202>
<010202>6</010202>
<010202>3</010202>
<010202>2</010202>
<010202>2</010202>
</result3>
<result3>
<010203>2</010203>
<010203>3</010203>
<010203>4</010203>
<010203>4</010203>
<010203>0</010203>
</result3>
<result4>1</result4>
<result4>4</result4>
<result4>6</result4>
<result4>4</result4>
<result4>1</result4>
<result5>
<010201>34</010201>
</result5>
<result5>
<010202>12</010202>
</result5>
<result5>
<010203>78</010203>
</result5>
<result6>41</result6>
I am facing no issues in creating complex types for result2, result4, result6 elements. But result1, result3 and result5 have an array of array of integers. How do i create an xsd for that ? Can anyone help ?

Consider trying an XSD to generate an XML like the below:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<result1>
<entry>
<key>010201</key>
<value>
<val>3</val>
<val>2</val>
<val>1</val>
</value>
</entry>
<entry>
<key>010201</key>
<value>
<val>3</val>
<val>2</val>
<val>1</val>
</value>
</entry>
</result1>
<result2>
<value>
<val>3</val>
<val>2</val>
<val>1</val>
</value>
</result2>
<result3>
<entry>
<key>010201</key>
<value>
<val>3</val>
<val>2</val>
<val>1</val>
</value>
</entry>
<entry>
<key>010201</key>
<value>
<val>3</val>
<val>2</val>
<val>1</val>
</value>
</entry>
</result3>
<result4>
<value>
<val>3</val>
<val>2</val>
<val>1</val>
</value>
</result4>
<result5>
<entry>
<key>010201</key>
<value>2</value>
</entry>
<entry>
<key>010201</key>
<value>2</value>
</entry>
</result5>
</root>
The xsd will be simpler for the above. Keeping the values as XML tags will not be feasible if the values will change.

Related

How to edit specific xml using xpath

I have got below xml which is genrated using xslt function json-to-xml(). I need to update this xml as shown in Result xml using given xpaths. I need the solution in java or xslt. Any help would be much appreciated.
XML
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<map key="Response">
<map key="Headers">
<string key="server">Lisa</string>
<string key="Status-Code">200</string>
<string key="Content-Type">applicaton/json</string>
</map>
<map key="Payload">
<map key="root">
<array key="cars">
<map>
<string key="company">ccc</string>
<string key="model">mmm</string>
</map>
<map>
<string key="strength">666</string>
<string key="Capacity">333</string>
</map>
</array>
<array key="bikes">
<map>
<string key="company">abc</string>
<string key="model">2018</string>
</map>
</array>
</map>
</map>
</map>
</map>
XPATHS
/Response/Payload/root/cars[2]/strength=999
/Response/Payload/root/bikes/model=2019
/Response/Headers/server=WebSphere
/Response/Headers/Content-Type=text
/Response/Payload/root/cars[2]/Capacity=555
/Response/Payload/root/cars[1]/model=mmm1
/Response/Payload/root/bikes/company=xyz
/Response/Payload/root/cars[1]/company=ccc1
/Response/Headers/Status-Code=400
UPDATED RESULT XML
<map xmlns="http://www.w3.org/2005/xpath-functions">
<map key="Response">
<map key="Headers">
<string key="server">WebSphere</string>
<string key="Status-Code">400</string>
<string key="Content-Type">text</string>
</map>
<map key="Payload">
<map key="root">
<array key="cars">
<map>
<string key="company">ccc1</string>
<string key="model">mmm1</string>
</map>
<map>
<string key="strength">999</string>
<string key="Capacity">555</string>
</map>
</array>
<array key="bikes">
<map>
<string key="company">xyz</string>
<string key="model">2019</string>
</map>
</array>
</map>
</map>
</map>
</map>
My Try
I have tried converting this xml back to json using xslt function and then used com.jayway.jsonpath Jayway JsonPath library to parse/change values of json on given xpaths. And then finally changed that json again to xml using xslt function. This worked for me like charm !!
But after using this library i started facing issues in my other part of application :( . All the post request with json request body started giving 400 error. The error was "Error 400 The request sent by the client was syntactically incorrect" . I couldn't figure out the issue and may be it was due to different jar conficts.
So I am trying some other way to work. Any other library like Jayway JsonPath? Or any other solution/Suggestion will help alot.
One approach given XSLT 3 might be to transform those paths you have into XSLT 3 match templates and then create a stylesheet you can execute with the transform function (https://www.w3.org/TR/xpath-functions/#func-transform):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
exclude-result-prefixes="xs"
version="3.0">
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="paths" as="xs:string">/Response/Payload/root/cars[2]/strength=999
/Response/Payload/root/bikes[1]/model=2019
/Response/Headers/server=WebSphere
/Response/Headers/Content-Type=text
/Response/Payload/root/cars[2]/Capacity=555
/Response/Payload/root/cars[1]/model=mmm1
/Response/Payload/root/bikes[1]/company=xyz
/Response/Payload/root/cars[1]/company=ccc1
/Response/Headers/Status-Code=400</xsl:param>
<xsl:param name="path-sequence" as="xs:string*" select="tokenize($paths, '\s+')!normalize-space()"/>
<xsl:variable name="stylesheet">
<axsl:stylesheet version="3.0">
<axsl:mode on-no-match="shallow-copy"/>
<xsl:for-each select="($path-sequence)">
<xsl:variable name="steps" select="tokenize(., '/')"/>
<axsl:template>
<xsl:attribute name="match">
<xsl:apply-templates select="tail($steps)" mode="step"/>
</xsl:attribute>
<axsl:copy>
<axsl:copy-of select="#*"/>
<xsl:value-of select="substring-after($steps[last()], '=')"/>
</axsl:copy>
</axsl:template>
</xsl:for-each>
</axsl:stylesheet>
</xsl:variable>
<xsl:template match=".[not(contains(., '[')) and not(contains(., '='))]" mode="step">
<xsl:if test="position() gt 1">/</xsl:if>
<xsl:sequence select="'*[#key = ''' || . || ''']'"/>
</xsl:template>
<xsl:template match=".[contains(., '=')]" mode="step">
<xsl:if test="position() gt 1">/</xsl:if>
<xsl:sequence select="'*[#key = ''' || substring-before(., '=') || ''']'"/>
</xsl:template>
<xsl:template match=".[contains(., '[')]" mode="step">
<xsl:if test="position() gt 1">/</xsl:if>
<xsl:sequence select="'*[#key = ''' || substring-before(., '[') || ''']/*[' || replace(., '^[^\[]+\[([0-9]+)\]', '$1') || ']'"/>
</xsl:template>
<xsl:template match="/">
<xsl:sequence select="transform(map {
'source-node' : .,
'stylesheet-node' : $stylesheet
})?output"/>
</xsl:template>
</xsl:stylesheet>
At https://xsltfiddle.liberty-development.net/jyyiVhv/1 I get the wanted result
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<map key="Response">
<map key="Headers">
<string key="server">WebSphere</string>
<string key="Status-Code">400</string>
<string key="Content-Type">text</string>
</map>
<map key="Payload">
<map key="root">
<array key="cars">
<map>
<string key="company">ccc1</string>
<string key="model">mmm1</string>
</map>
<map>
<string key="strength">999</string>
<string key="Capacity">555</string>
</map>
</array>
<array key="bikes">
<map>
<string key="company">xyz</string>
<string key="model">2019</string>
</map>
</array>
</map>
</map>
</map>
</map>
that way although I had to adapt the paths including bikes to bikes[1].

Reading an Xml file into map

I have an xml string in the following format
<map>
<entry>
<string>key</string>
<string>value</string>
</entry>
<entry>
<string>key2</string>
<string>value2</string>
</entry>
....
</map>
Is there an easy library/tool that I can use to read this type of xml directly into a Hashmap. I am not very familiar with working with xml, so I would really appreciate some help here.
Thanks.

schema for hudson job config.xml

am new to HUDSON ci-server . i have a requirement stating that i have to use Hudson remote access API and create new jobs in hudson or edit the existing job's configuration file and update it.
I have a sample config.xml file .
<?xml version='1.0' encoding='UTF-8'?>
<project>
<actions/>
<description>Free style Basic sample Job for POC . will create this job with all the required fields . then will take this config.xml and will try to validate and study this schema .</description>
<project-properties class="java.util.concurrent.ConcurrentHashMap">
<entry>
<string>hudson-plugins-disk_usage-DiskUsageProperty</string>
<base-property>
<originalValue class="hudson.plugins.disk_usage.DiskUsageProperty"/>
<propertyOverridden>false</propertyOverridden>
</base-property>
</entry>
<entry>
<string>logRotator</string>
<log-rotator-property>
<originalValue class="hudson.tasks.LogRotator">
<daysToKeep>5</daysToKeep>
<numToKeep>-1</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</originalValue>
<propertyOverridden>false</propertyOverridden>
</log-rotator-property>
</entry>
<entry>
<string>scmCheckoutRetryCount</string>
<integer-property>
<originalValue class="int">5</originalValue>
<propertyOverridden>false</propertyOverridden>
</integer-property>
</entry>
<entry>
<string>hudson-tasks-Mailer</string>
<external-property>
<originalValue class="hudson.tasks.Mailer">
<recipients>abc#example.com</recipients>
<dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild>
<sendToIndividuals>false</sendToIndividuals>
</originalValue>
<propertyOverridden>false</propertyOverridden>
<modified>true</modified>
</external-property>
</entry>
<entry>
<string>hudson-plugins-build_timeout-BuildTimeoutWrapper</string>
<external-property>
<originalValue class="hudson.plugins.build_timeout.BuildTimeoutWrapper">
<timeoutMinutes>5</timeoutMinutes>
<failBuild>false</failBuild>
</originalValue>
<propertyOverridden>false</propertyOverridden>
<modified>true</modified>
</external-property>
</entry>
<entry>
<string>builders</string>
<describable-list-property>
<originalValue class="hudson.util.DescribableList">
<hudson.tasks.Ant>
<targets></targets>
<antName>org.apache.ant_1.7.1</antName>
</hudson.tasks.Ant>
<hudson.tasks.Shell>
<command>HUDSON_USER</command>
</hudson.tasks.Shell>
</originalValue>
<propertyOverridden>false</propertyOverridden>
</describable-list-property>
</entry>
<entry>
<string>hudson-triggers-SCMTrigger</string>
<trigger-property>
<originalValue class="hudson.triggers.SCMTrigger">
<spec>#daily</spec>
</originalValue>
<propertyOverridden>false</propertyOverridden>
</trigger-property>
</entry>
<entry>
<string>jdk</string>
<string-property>
<originalValue class="string">(Inherit From Job)</originalValue>
<propertyOverridden>false</propertyOverridden>
</string-property>
</entry>
<entry>
<string>hudson-tasks-ArtifactArchiver</string>
<external-property>
<originalValue class="hudson.tasks.ArtifactArchiver">
<compressionType>GZIP</compressionType>
<latestOnly>false</latestOnly>
<autoValidateFileMask>false</autoValidateFileMask>
</originalValue>
<propertyOverridden>false</propertyOverridden>
<modified>true</modified>
</external-property>
</entry>
<entry>
<string>scm</string>
<scm-property>
<originalValue class="hudson.scm.NullSCM"/>
<propertyOverridden>false</propertyOverridden>
</scm-property>
</entry>
<entry>
<string>hudson-plugins-release-ReleaseWrapper</string>
<external-property>
<originalValue class="hudson.plugins.release.ReleaseWrapper">
<releaseVersionTemplate></releaseVersionTemplate>
<doNotKeepLog>false</doNotKeepLog>
<overrideBuildParameters>false</overrideBuildParameters>
<parameterDefinitions/>
<preBuildSteps/>
<postBuildSteps/>
<postSuccessfulBuildSteps/>
<postFailedBuildSteps/>
</originalValue>
<propertyOverridden>false</propertyOverridden>
<modified>true</modified>
</external-property>
</entry>
</project-properties>
<keepDependencies>false</keepDependencies>
<creationTime>1403865219075</creationTime>
<properties/>
<cascadingChildrenNames class="java.util.concurrent.CopyOnWriteArraySet"/>
<cascading-job-properties class="java.util.concurrent.CopyOnWriteArraySet">
<string>hudson-plugins-batch_task-BatchTaskProperty</string>
<string>hudson-plugins-disk_usage-DiskUsageProperty</string>
<string>hudson-plugins-jira-JiraProjectProperty</string>
<string>org-hudsonci-plugins-snapshotmonitor-WatchedDependenciesProperty</string>
<string>hudson-plugins-promoted_builds-JobPropertyImpl</string>
</cascading-job-properties>
<scm class="hudson.scm.NullSCM"/>
<canRoam>false</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<concurrentBuild>false</concurrentBuild>
<cleanWorkspaceRequired>false</cleanWorkspaceRequired>
</project>
Now i have a tag called project-properties . in it i have multiple entry tags .each enrty tag has some sub tags among which string is common to each entry tag .I want to access all these different tags through java using Hudosn remote access API .
for example :
<entry>
<string>logRotator</string>
<log-rotator-property>
<originalValue class="hudson.tasks.LogRotator">
<daysToKeep>5</daysToKeep>
<numToKeep>-1</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</originalValue>
<propertyOverridden>false</propertyOverridden>
</log-rotator-property>
</entry>
so i want to acceess daysToKeep numToKeep artifactDaysToKeep and so on for the rest of tags and other tags present in the config.xml
Any help will be appreciated.
Thanks in advance.
You could do this by getting an instance of the Item and then updating the project configuration by using the following code
Source streamSource = new StreamSource(new StringReader(config));
try {
proj.updateByXml(streamSource);
} catch (IOException ex) {
Logger.getLogger(PluginImpl.class.getName()).log(Level.SEVERE, null, ex);
}
the config is the string generated config file.
For more info refer to this post How to update Jenkins config.xml from Java code?

XStream with HashMap<String,String>

Anyone could tell me how to Serialize a HashMap with XStream?
private HashMap<String,String> attributes;
attributes = new HashMap<String,String>();
attributes.put("Description","Value");
attributes.put("Description2","Value2");
attributes.put("Description3","Value3");
My xml looks like
<attributes>
<entry>
<string>Description</string>
<string>value</string>
</entry>
<entry>
<string>Description2</string>
<string>Value2</string>
</entry>
<entry>
<string>Description3</string>
<string>Value3</string>
</entry>
</attributes>
I want an output like
<attributes>
<attr>
<description>Description</description>
<value>Value</value>
</attr>
<attr>
<description>Description2</description>
<value>Value2</value>
</attr>
<attr>
<description>Description3</description>
<value>Value</value>
</attr>
</attributes>
how can achieve that using XStream? Is possible with annotations?
If you are using XStream 1.4.5, you have the NamedMapConverter to do what you want.
Just register the converter showing how you want to marshal your map as the example bellow:
XStream xstream = new XStream();
NamedMapConverter namedMapConverter = new NamedMapConverter(xstream.getMapper(),"attr","description",String.class,"value",String.class);
xstream.registerConverter(namedMapConverter);

Remove XML content retaining a given Node (Java parser)

In the XML example below, using a java parser how to keep the content under the tag AND followed by center and remove everything else?
The tag might have other instances when is followed by other tags than center, and those has to be discarded.
<xml>
<A>
<B>
.
.
.
<parameter>
<parameterid>center</parameterid>
<name>Center</name>
<keyframe>
<when>1</when>
<value>
<horiz>100</horiz>
<vert>100</vert>
</value>
</keyframe>
<keyframe>
<when>2</when>
<value>
<horiz>150</horiz>
<vert>150</vert>
</value>
</keyframe>
</parameter>
<parameter>
...
</parameter>
<parameter>
...
</parameter>
.
.
.
</B>
</A>
</xml>
So the output will look like:
<parameter>
<parameterid>center</parameterid>
<name>Center</name>
<keyframe>
<when>1</when>
<value>
<horiz>100</horiz>
<vert>100</vert>
</value>
</keyframe>
<keyframe>
<when>2</when>
<value>
<horiz>150</horiz>
<vert>150</vert>
</value>
</keyframe>
</parameter>
Please advise. Thanks!
You can use Java Regexp to remove unneeded content, and then parse only needed part f.e.
String sourceXML = readFileToString("source.xml")
final Pattern pattern = Pattern.compile(".*(<parameter>.+</parameter>).*",Pattern.DOTALL);
Matcher matcher = pattern.matcher(sourceXML);
if (matcher.find()) {
String xmlToParse = matcher.group(0);
someDomOrSaxParser.parseFromString(xmlToParse)
}else
System.out.println("NO MATCH");
This would be a good job for an XSLT stylesheet.
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:apply-templates select="node()|#*"/>
</xsl:template>
<xsl:template match="parameter[parameterid='center']">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
applied to the input in the question, produces the following output:
<parameter>
<parameterid>center</parameterid>
<name>Center</name>
<keyframe>
<when>1</when>
<value>
<horiz>100</horiz>
<vert>100</vert>
</value>
</keyframe>
<keyframe>
<when>2</when>
<value>
<horiz>150</horiz>
<vert>150</vert>
</value>
</keyframe>
</parameter>
If you have any questions on using XSLT in Java, please take a look at this question.

Categories

Resources