I have a XML file in the following format:
<CodeSnippet>
<Code tag="class eclipse">
<Snippet>sample</Snippet>
<TimeStamp>05/11/2014 13:50:36</TimeStamp>
</Code>
<Code tag="button java">
<Snippet>Sample code</Snippet>
<TimeStamp>05/11/2014 12:36:36</TimeStamp>
</Code>
.
.
.
</CodeSnippet>
I would like to know, how to retrieve the last 5 child nodes of the root node "CodeSnippet" and display the text inside the tag "Snippet".
Get a learning of using XPATH expressions in java here http://howtodoinjava.com/2012/11/07/how-to-work-with-xpaths-in-java-with-examples/
For your specific problem get all the snippet nodes using xpath expression //CodeSnippet/Snippet. Once done run a for loop from nodes.length to nodes.length-5.
Try something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<root>
<xsl:for-each select="CodeSnippet/Code[position() > last() - 5]">
<xsl:copy-of select="Snippet"/>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
You didn't say what the exact format of output should be. The above will result in an XML document in the form of:
<?xml version="1.0" encoding="utf-8"?>
<root>
<Snippet>V</Snippet>
<Snippet>W</Snippet>
<Snippet>X</Snippet>
<Snippet>Y</Snippet>
<Snippet>Z</Snippet>
</root>
This is a good tutorial of XML Parsing for Java using three different technologies. In your case I would recommend you the DOM option, even if I see SAX the easiest one. Just try to make the changes you need for your case.
http://www.javacodegeeks.com/2013/05/parsing-xml-using-dom-sax-and-stax-parser-in-java.html
Have a nice code!
If you can use an XPath 2.0 processor, you could use the following XPath:
subsequence(//Snippet,count(//Snippet)-5)
Related
I have some complex xml structure. Some times i want to keep only the elements match my runtime list of xpath entries.
Sample xml
<Employee>
<Address>
<addressLine1>Dummy Line 1</addressLine1>
<zip>535270</zip>
</Address>
<Department>
<id>102</id>
<name>development</name>
</Department
</Employee>
Sample xpath entries can be some time like
//Employee/Address
//Employee/Department/
//Employee/Department/name
In the above xpath if you observe we have Department and Name inside department then in that case I can ignore Department.Also above xpath entries can be as below too
//Employee/Address
//Employee/Department/name
Resultant xml i want as below
<Employee>
<Address>
<addressLine1>Dummy Line 1</addressLine1>
<zip>535270</zip>
</Address>
<Department>
<name>development</name>
</Department
</Employee>
I realized I can achieve this through xslt. So I want the xslt for this kind of generic requirement. Also my current code is in java. Is there any better alternative in java??
I have to admit that I do not fully understand your requirements, but what I do see is that:
You have a set of XPath
You seem to want to get the union of these XPath statements if applied to your input document
Duplicates removed (just like XPath union expression)
Some magic about certain elements that may appear even if they are not in the XPath statement list.
My original reflex was: use xsl:evaluate, but considering you are rooting all your XPath expressions, this may not give you the results you want. Also, it requires an XSLT 3.0 processor.
With XSLT 2.0, you could do something like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*" />
<xsl:output indent="yes" />
<xsl:variable name="patterns" as="xs:string*">
<xsl:sequence select="(
'foo/bar',
'foo/test',
'foo/bar/zed')" />
</xsl:variable>
<xsl:template match="node()[true() = (
for $p in $patterns
return ends-with(
string-join(current()/ancestor-or-self::*/name(),
'/'), $p))]">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
It is just meant to get you started, it is not meant as a full-fledged solution. It matches XPath of the production //QName/QName, like the one in your example. I removed the trailing //, and simply match when the current path matches any of the paths (taking into account an implicit descendent-or-self, as in your example).
You probably want to wrap the for-expression in a function and call the function to map the concatenation of the current path to any of your paths in your list.
In its current form, you will also need to supply the paths leading up to a deeper path, or you will have to implement an fn:snapshot-like function to copy the ancestor nodes as well.
Anyway, I think this is a simple enough approach to mimic not necessarily xsl:evaluate, but mimic pattern matching based on a path, as your question seems to imply.
I'm trying to validate an XML file, but I get the following error:
Can not find declaration of element
'xsl:stylesheet'.
This is the XML:
<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt' exclude-result-prefixes='msxsl' xmlns:ns='http://www.ibm.com/wsla'>
<xsl:strip-space elements='*'/>
<xsl:output method='xml' indent='yes'/>
<xsl:template match='#* | node()'>
<xsl:copy>
<xsl:apply-templates select='#* | node()'/>
</xsl:copy>
</xsl:template>
<xsl:template match="/ns:SLA/ns:ServiceDefinition/ns:WSDLSOAPOperation/ns:SLAParameter/#name[.='TotalMemoryConsumption']">
<xsl:attribute name='{name()}'>
<xsl:text>MemConsumption</xsl:text>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Where is the mistake?
EDIT: I want to parse this XML in Java with SAX, but I get the following error:
Element type "xsl:template" must be followed by either attribute specifications, ">" or "/>".
How to get rid of it?
Assuming you are actually trying to validate your XSL as an XML document, it looks like that website requires you to point to a schema or DTD in order to validate the XML against it. You can get a non-normative schema here: http://www.w3.org/TR/xslt20/#schema-for-xslt. Here's instructions on how to reference a schema from an XML file: http://www.ibm.com/developerworks/xml/library/x-tipsch.html
You could also check "Well-Formedness only," and check the document for well-formedness, if not actually validity.
Generally, any XSL engine will report any errors in your XSL document, so you don't need to validate it separately.
Your XSL is OK, don't worry. Just that there is no DTD/XSD for XSLs 1.0. no one bothers checking XSLT stylesheets (1.0) for validity. "Wellformedness" is enough.
This question is a follow up to my earlier question:
Creating a valid XSD that is open using <all> and <any> elements
Given that I have a Java String containing an XML document of the following form:
<TRADE>
<TIME>12:12</TIME>
<MJELLO>12345</MJELLO>
<OPTIONAL>12:12</OPTIONAL>
<DATE>25-10-2011</DATE>
<HELLO>hello should be ignored</HELLO>
</TRADE>
How can I use XSLT or similar (in Java by using JAXB) to remove all elements not contained in a set of elements.
In the above example I am only interested in (TIME, OPTIONAL, DATE), so I would like to transform it into:
<TRADE>
<TIME>12:12</TIME>
<OPTIONAL>12:12</OPTIONAL>
<DATE>25-10-2011</DATE>
</TRADE>
The order of the elements is not fixed.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNames" select="'|TIME|OPTIONAL|DATE|'"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*/*">
<xsl:if test="contains($pNames, concat('|', name(), '|'))">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<TRADE>
<TIME>12:12</TIME>
<MJELLO>12345</MJELLO>
<OPTIONAL>12:12</OPTIONAL>
<DATE>25-10-2011</DATE>
<HELLO>hello should be ignored</HELLO>
</TRADE>
produces the wanted, correct result:
<TRADE>
<TIME>12:12</TIME>
<OPTIONAL>12:12</OPTIONAL>
<DATE>25-10-2011</DATE>
</TRADE>
Explanation:
The identity rule (template) copies every node "as-is".
The identity rule is overridden by a template matching any element that is not the top element of the document. Inside the template a check is made if the name of the matched element is one of the names specified in the external parameter $pNames in a pipe-delimited string of wanted names.
See the documentation of your XSLT processor on how to pass a parameter to a transformation -- this is implementation-dependent and differs from processor to processor.
I haven't tried yet, but maybe the javax.xml.tranform package can help:
http://download.oracle.com/javase/6/docs/api/javax/xml/transform/package-summary.html
JAXB & XSLT
JAXB integrates very cleanly with XSLT for an example see:
How to get jaxb to Ignore certain data during unmarshalling
Your Other Question
Based on your previous question (see link below), the transform is really unnecessary as JAXB will just ignore attributes and elements that are not mapped to fields/properties in your domain object.
Creating a valid XSD that is open using <all> and <any> elements
I am having a certian issue with special characters in my XML.
Bascially I am splitting up an xml into multiple xmls using Xalan Processor.
When splitting the documents up I am using their value of the name tag as the name of the file generated. The problem is that the name contains characters that arent recognized by the XML processor like ™ (TM) and ® (R). I want to remove those characters ONLY when naming the files.
<xsl:template match="products">
<redirect:write select="concat('..\\xml\\product\\en\\',translate(string(name),'</> ',''),'.xml')">
The above is the XSL code I have writter to split the XML into multlpe XMLs. As you can see I am using hte translate method to subtitute '/','<','>' with '' from the name. I was hoping I could do the same with ™ (TM) and ® (R) but it doesnt seem to work.
Please advice me how I would be able to do that.
Thanks for you help in advance.
I don't have Xalan, but with 8 other XSLT processors this thransformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()">
<xsl:value-of select="translate(., '</>™®', '')"/>
===================
<xsl:value-of select="translate(., '</>™®', '')"/>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>XXX™ My Trademark®</t>
produces the wanted result:
XXX My Trademark
===================
XXX My Trademark
I suggest that you try to use one of the two expressions above -- at least the second may work successfully.
Following Dimitre answer, I think that if you are not sure about wich special character could be in name, maybe you should keep what you consider legal document's name characters.
As example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()">
<xsl:value-of select="translate(.,
translate(.,
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ',
''),
'')"/>
</xsl:template>
</xsl:stylesheet>
With input:
<t>XXX™ My > Trademark®</t>
Result:
XXX My Trademark
I'm working with a DSL based on an XML schema that supports functional language features such as loops, variable state with context, and calls to external Java classes. I'd like to write a tool which takes the XML document and converts it to, at the very least, something that looks like Java, where the <set> tags get converted to variable assignments, loops get converted to for loops, and so on.
I've been looking into ANTLR as well as standard XML parsers, and I'm wondering whether there's a recommended way to go about this. Can such an XML document be converted to something that's convertable to Java, if not directly?
I'm willing to write the parsing through SAX that writes an intermediate language based on each tag, if that's the recommended way, but the part that's giving me pause is the fact that it's context-based in the same way a language like Scheme is, with child elements of any tag being fully evaluated before the parent.
You can do it with XSLT. Then just use to generate the code snippets you need.
(remember to set the output format to plain text)
EDIT: Sample XSLT script
Input - a.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="b.xsl"?>
<set name='myVar'>
<concat>
<s>newText_</s>
<ref>otherVar</ref>
</concat>
</set>
Script - b.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="text" />
<xsl:template match="set">
<xsl:value-of select="#name"/>=<xsl:apply-templates/>
</xsl:template>
<xsl:template match="concat">
<xsl:for-each select="*">
<xsl:if test="position() > 1">+</xsl:if>
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template match="ref">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="s">
<xsl:text>"</xsl:text>
<xsl:apply-templates/>
<xsl:text>"</xsl:text>
</xsl:template>
</xsl:stylesheet>
Note that a.xml contain an instruction that will let XSLT-capable browsers render it with the stylesheet b.xsl. Firefox is such a browser. Open a.xml in firefox and you will see
myVar="newText_"+otherVar
Note that XSLT is a quite capable programming language, so there is a lot you can do.