How can i remove commented lines from XHTML using XSLT ,
Example : test.xtml
<html>
<head/>
<body>
This is Test Code.
<!--Test Comment -->
</body>
</html>
XSLT :: The below XSLT gives warning " Severity: warning Description: Ambiguous rule match for html[1]/body[1]/comment()[1] Matches both "comment()" on line 10 of remove_comment.xsl
and "node()|#*" on line 4 of remove_comment.xsl "
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="comment()"/>
Give the template on line 10 with match="comment()" a higher priority e.g. <xsl:template match="comment()" priority="5"/>.
Related
I am using following xslt
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.test.com/services/test/test/v1">
<xsl:output method="xml" encoding="UTF-8"
omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:variable name="mytree">
<xsl:call-template name="myvariable">
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="count($mytree/foos/foo) > 1">
<xsl:copy-of select="$mytree"/>
</xsl:when>
<xsl:otherwise>
<error>test</error>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="myvariable">
<foos>
<foo>bar1</foo>
<foo>bar2</foo>
<foo>bar3</foo>
<foo>bar4</foo>
</foos>
</xsl:template>
</xsl:stylesheet>
When i use above xslt it should be following output
<foos xmlns="http://www.test.com/services/test/test/v1">
<foo>bar1</foo>
<foo>bar2</foo>
<foo>bar3</foo>
<foo>bar4</foo>
</foos>
but it is
<error xmlns="http://www.test.com/services/test/test/v1">test</error>
when i remove the xmlns="http://www.test.com/services/test/test/v1" output is proper. Not sure what is happening?
Well, with any XML, whether constructed inside of your XSLT or read from a source, if you have elements in a certain namespace, then, to select them with XPath in XSLT, in XSLT 2 you have two options, either use xpath-default-namespace="http://www.test.com/services/test/test/v1" (e.g. <xsl:when test="count($mytree/foos/foo) > 1" xpath-default-namespace="http://www.test.com/services/test/test/v1">) or bind the namespace to a prefix (e.g. <xsl:when xmlns:v1="http://www.test.com/services/test/test/v1" test="count($mytree/v1:foos/v1:foo) > 1">).
You can use these approaches on an ancestor element, for instance the root element of the stylesheet, if it does not interfere with other selections you want to make.
You have to specify qualified element names in your XPath expression to address the foos and foo elements in your default namespace http://www.test.com/services/test/test/v1:
Register the default namespace once more with a namespace prefix (e.g. myns): xmlns:myns="http://www.test.com/services/test/test/v1"
Use that namepace prefix in your XPath expressions to address nodes in that namespace (e.g. myns:foos/myns:foo).
Add exclude-result-prefixes="myns" to suppress the myns prefix in your result document.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.test.com/services/test/test/v1"
xmlns:myns="http://www.test.com/services/test/test/v1"
exclude-result-prefixes="myns">
…
<xsl:template match="/">
…
<xsl:choose>
<xsl:when test="count($mytree/myns:foos/myns:foo) > 1">
<xsl:copy-of select="$mytree"/>
</xsl:when>
<xsl:otherwise>
<error>test</error>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
…
</xsl:stylesheet>
see XSLT Fiddle
If you only had an XSLT 1.0 processor at hand, you would need the EXSLT node-set function to access the $mytree variables from the result tree:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.test.com/services/test/test/v1"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
xmlns:myns="http://www.test.com/services/test/test/v1"
exclude-result-prefixes="myns">
…
<xsl:template match="/">
…
<xsl:choose>
<xsl:when test="count(exsl:node-set($mytree)/myns:foos/myns:foo) > 1">
<xsl:copy-of select="$mytree"/>
</xsl:when>
<xsl:otherwise>
<error>test</error>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
…
</xsl:stylesheet>
Use code for remove namespace
<xsl:template match="#*[namespace-uri() = 'http://www.test.com/services/test/test/v1']"/>
I have one XML file that I need to transform based on a mapping file with XSLT 2.0. I'm using the Saxon HE processor.
My mapping file:
<element root="TEST">
<childName condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILD</childName>
<childBez condition="/TEST/MyElement/CHILD[text()='B']>/TEST/MyElement/CHILDBEZ</childBez>
</element>
I have to copy the elements CHILD and CHILDBEZ plus the parent and the root elements when the text of CHILD equals B.
So with this Input:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<CHILD>A</CHILD>
<CHILDBEZ>ABEZ</CHILDBEZ>
<NotInteresting></NotInteresting>
</MyElement>
<MyElement>
<CHILD>B</CHILD>
<CHILDBEZ>BBEZ</CHILDBEZ>
<NotInteresting2></NotInteresting2>
</MyElement>
</TEST>
the desired output:
<TEST>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>
what I have so far (based on this solution XSLT 2.0 XPATH expression with variable):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:param name="mapping" select="document('mapping.xml')"/>
<xsl:key name="map" match="*" use="."/>
<xsl:template match="/">
<xsl:variable name="first-pass">
<xsl:apply-templates mode="first-pass"/>
</xsl:variable>
<xsl:apply-templates select="$first-pass/*"/>
</xsl:template>
<xsl:template match="*" mode="first-pass">
<xsl:param name="parent-path" tunnel="yes"/>
<xsl:variable name="path" select="concat($parent-path, '/', name())"/>
<xsl:variable name="replacement" select="key('map', $path, $mapping)"/>
<xsl:variable name="condition" select="key('map', $path, $mapping)/#condition"/>
<xsl:choose>
<xsl:when test="$condition!= ''">
<!-- if there is a condition defined in the mapping file, check for it -->
</xsl:when>
<xsl:otherwise>
<xsl:element name="{if ($replacement) then name($replacement) else name()}">
<xsl:attribute name="original" select="not($replacement)"/>
<xsl:apply-templates mode="first-pass">
<xsl:with-param name="parent-path" select="$path" tunnel="yes"/>
</xsl:apply-templates>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[#original='true' and not(descendant::*/#original='false')]"/>
</xsl:stylesheet>
but the problem is that it's impossible to evaluate dynamic XPATH expressions with XSLT 2.0. Does anyone knows a workaround for that? Plus I have a problem with the mapping file. When there is only one element in it, it's not working at all.
If dynamic XPath evaluation isn't an option in your chosen processor, then generating an XSLT stylesheet is often a good alternative. In fact, it's often a good alternative anyway.
One way of thinking about this is that your mapping file is actually a program written in a very simple transformation language. There are two ways of executing this program: you can write an interpreter (dynamic XPath evaluation), or you can write a compiler (XSLT stylesheet generation). Both work well.
I've the below cases.
**Case1:**
<para>1A/66</para>
<para>1A/34S/4</para>
<para>1/66</para>
**Case 2:**
<para>A/66</para>
<para>A1/1</para>
Here, the explaination is if the para starts with a letter (here it is A, it can be any alphabet), it should print case 2 else it should print case 1.
please let me know how can i do this.
Here is a DEmo
With XSLT 2.0 you have regular expression support so using e.g.
<xsl:template match="para[matches(., '^[a-zA-Z]')]">case 2</xsl:template>
<xsl:template match="para[matches(., '^[^a-zA-Z]')]">case 1</xsl:template>
Of course you can use a different regular expression to match on non-ASCII letters as well if "can be any alphabet" is meant to indicate other letters.
Here you are :
<xsl:template match="/">
<hmtl>
<head>
<title>New Version!</title>
</head>
<body>
<xsl:call-template name="print-param" />
<xsl:apply-templates select="child::*"/>
</body>
</hmtl>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match = "body">
<!-- Match cases -->
</xsl:template>
<xsl:template name = "print-param">
<!-- Match cases -->
**Case1:**
<xsl:for-each select=".//para[matches(., '^[A-Za-z]\.*')]">
<para><xsl:value-of select="." /></para>
</xsl:for-each>
**Case 2:**
<xsl:for-each select=".//para[not(matches(., '^[A-Za-z]\.*'))]">
<para><xsl:value-of select="." /></para>
</xsl:for-each>
</xsl:template>
</xsl:transform>
Check this demo
In a xsl:stylesheet I have this "identity like" transform, to eliminate comments, empty (terminal) tags and empty attributes... But the second xsl:when not works
<xsl:template match="node()">
<xsl:choose>
<xsl:when test="name()='p' and not(./*) and not(normalize-space(.))"></xsl:when>
<xsl:when test="not(name()='img') and not(name()='br') and not(./*) and not(text())"
></xsl:when> <!-- this line NOT WORKS -->
<xsl:otherwise><xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#*">
<xsl:choose>
<xsl:when test="not(normalize-space(.))"></xsl:when>
<xsl:otherwise><xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="comment()"></xsl:template>
Whow to express condition to empty tags in this context?
PS: the "empty rules" are explained here, I try to use it, but not see why not working.
An empty element is an element with no child nodes.
Template match priority is your friend ... the following should be the kind of identity stylesheet that meets your description plus what I think you are doing with image and break elements.
<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!--toss these-->
<xsl:template match="comment() |
*[not(node())] |
#*[not(normalize-space())]"/>
<!--preserve these-->
<xsl:template match="img|br" priority="1">
<xsl:call-template name="identity"/>
</xsl:template>
<!--preserve everything else-->
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Working with XHTML and XML tools, sometimes we need to invert the italics <i> blocks. Example:
<!-- original text: -->
<p id="p1"><i>Several more</i> Homo sapiens <i>fossils were discovered</i>.</p>
<!-- same text, swapping italics: -->
<p id="p2">Several more <i>Homo sapiens</i> fossils were discovered.</p>
So, looks like this,
Several more Homo sapiens fossils were discovered.
Several more Homo sapiens fossils were discovered.
There are many ways to transform a "mixed italics" text into a "inverted italics": see
What the correct algorithm to invert italics in a mixed text?...
... But I not see any way to do it with "pure XSLT" (without external processing dependences): do you see?
Something like this:
<xsl:template match="i" mode="invert-italic">
<xsl:apply-templates mode="invert-italic"/>
</xsl:template>
<xsl:template match="text()[not(ancestor::i)]" mode="invert-italic">
<i><xsl:copy-of select="."/></i>
</xsl:template>
<xsl:template match="node()" mode="invert-italic">
<xsl:copy>
<xsl:copy select="#*"/>
<xsl:apply-templates mode="invert-italic"/>
</xsl:copy>
</xsl:template>
I'm not sure if this would cover all cases, but you could do this:
XML Input
<html>
<!-- original text: -->
<p id="p1"><i>Several more</i> Homo sapiens <i>fossils were discovered</i>.</p>
<!-- same text, swapping italics: -->
<p id="p2">Several more <i>Homo sapiens</i> fossils were discovered.</p>
<p>Leave me alone!</p>
<p><b><i>O</i>RIGINAL <big><i>with italics</i> and </big> withOUT</b></p>
</html>
XSLT 1.0
<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:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[i]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="node()" mode="swapItal"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" mode="swapItal" priority="1">
<i><xsl:value-of select="."/></i>
</xsl:template>
<xsl:template match="i" mode="swapItal">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="#*|node()" mode="swapItal">
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="swapItal"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<html>
<!-- original text: -->
<p id="p1">Several more<i> Homo sapiens </i>fossils were discovered<i>.</i></p>
<!-- same text, swapping italics: -->
<p id="p2"><i>Several more </i>Homo sapiens<i> fossils were discovered.</i></p>
<p>Leave me alone!</p>
<p><b>O<i>RIGINAL </i><big>with italics<i> and </i></big><i> withOUT</i></b></p>
</html>
Input Rendered
Several more Homo sapiens fossils were discovered.
Several more Homo sapiens fossils were discovered.
Leave me alone!
ORIGINAL with italics and withOUT
Output Rendered
Several more Homo sapiens fossils were discovered.
Several more Homo sapiens fossils were discovered.
Leave me alone!
ORIGINAL with italics and withOUT
Hello? Someone else will edit? ... Ok, I need "100% solution", them I am adding one, only for finesh, but was not "my".
#MichaelKay and #DanielHaley show good clues and near to fineshed solutions (!).
XML Input
<html>
<p><i>Several more</i> Homo sapiens <i>fossils were discovered</i>.</p>
<p>Several more <i>Homo sapiens</i> fossils were discovered.</p>
<p>Leave me alone!</p>
<p><b><i>F</i>RAGMENT <big><i>with italics</i> and </big> withOUT</b></p>
<p><i><sup><sub><sup><sub>Deep tags</sub></sup></sub></sup> here</i>
<big><b><small>and here</small></b></big>!
</p>
</html>
XSLT 1.0 implemention
#DanielHaley show better results (only the <p>Leave me alone!</p> not inverted), but #MichaelKay's solution is more elegant: I merged both to produce this "100% solution". Now I am using this XSLT as "swap italics algorithm" on my system... No bugs until now (!).
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="p"/>
<xsl:template match="#*|node()"> <!-- copy all -->
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="i"> <!-- remove tag i -->
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()[not(ancestor::i)]"> <!-- inlcude tag i -->
<i><xsl:copy-of select="."/></i>
</xsl:template>
</xsl:stylesheet>
Outlining as an "drive by event algorithm" in a copy process:
remove i tags: copy any thing of "<i> thing </i>" as " thing ".
include i tags: copy any text as "<i> text </i>", when the text is not into a context of "italic parents (or another ancestor)". PS: text is a terminal node of the DOM tree.