Input html style::
border: #5f497a 3pt solid;
or
border: 3pt #5f497a solid;
or
border: solid #5f497a 3pt;
Hi all,
These all are my possible html input style from which i have to fetch only the border width (3) using xslt 1.0. Please help me..Thanks in advance..
Note:I will have always one digit before pt
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:template match="table">
<xsl:apply-templates select="#style"/>
</xsl:template>
<xsl:template match="#style">
<xsl:if test="string-length() >0">
<xsl:variable name="vValues"
select="substring-after(.,':')"/>
<xsl:variable name="vNormalized" select=
"translate(normalize-space(concat(';',$vValues)),
' ',
';')
"/>
<xsl:variable name="vEndingWidth" select=
"substring-before($vNormalized,'pt;')"/>
<xsl:variable name="vLength"
select="string-length($vEndingWidth)"/>
<xsl:value-of select="substring($vEndingWidth, $vLength)"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document:
<t>
<table style="border: #5f497a 3pt solid;"/>
<table style="border: 3pt #5f497a solid;"/>
<table style="border: solid #5f497a 3pt;"/>
</t>
produces the wanted, correct results:
3
3
3
Related
I want to add multiple matches in except operator.
Example:
<root>
<div>
<span style="font-family:'Work Sans', sans-serif;">
</span>
<h3>hi</h3>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p>
</div>
</root>
Expected result: Want to convert div tag to p tag and then move only h3,ol,ul,p tag out of it if present.
<root>
<p>
<span style="font-family:'Work Sans', sans-serif;">
</span>
</p>
<h3>hi</h3>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p>
</root>
I tried this:
<xsl:template match="div">
<p>
<xsl:copy-of select="* except h3"/>
</p>
<xsl:copy-of select="h3"/>
</xsl:template>
Above xslt results to :
<root>
<p>
<span style="font-family:'Work Sans', sans-serif;">
</span>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p>
</p>
<h3>hi</h3>
</root>
Is there any way to add mutiple element names in except operator like <xsl:copy-of select="* except h3 and ol"/>
Another approach i tried:
<xsl:template match="div[p | ol | ul | h3 | h2]">
<xsl:apply-templates/>
</xsl:template>
<!-- convert <div> to <p> if it's direct child is not one of p,ol,ul -->
<xsl:template match="div[not(p | ol | ul | h3 | h2)]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
And this results to which is wrong as i still want span tag to be under p tag:
<root><span style="font-family:'Work Sans', sans-serif;">
</span>
<h3>hi</h3>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p></root>
In stead of using xsl:copy you could just use the xsl:apply-templates approach like this:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="node()|#*" name="copy">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="div/span">
<p>
<xsl:call-template name="copy"/>
</p>
</xsl:template>
</xsl:stylesheet>
The except operator was introduced in XPath 2.0 so it doesn't make any sense on how to use it with XSLT 1.0 which uses XPath 1.0.
As for its use where supported, you can of course do e.g. * except (h3, ol).
In XPath 1.0 you can try e.g. *[not(self::h3|self::ol)].
I want to get the first heading (h1) before a table in a docx.
I can get all headings with:
<xsl:template match="w:p[w:pPr/w:pStyle[#w:val='berschrift1']]">
<p>
<context>
<xsl:value-of select="." />
</context>
</p>
</xsl:template>
and I can also get all tables
<xsl:template match="w:tbl">
<p>
<table>
<xsl:value-of select="." />
</table>
</p>
</xsl:template>
But unfortunetly the processor does not accept
<xsl:template match="w:tbl/preceding-sibling::w:p[w:pPr/w:pStyle[#w:val='berschrift1']]">
<p>
<table>
<xsl:value-of select="." />
</table>
</p>
</xsl:template>
Here is a reduced XML file extracted from a docx: http://pastebin.com/KbUyzRVv
I want something like that as a result:
<context>Let’s get it on</context> <- my heading
<table>data</table>
<context>Let’s get it on</context> <- my heading
<table>data</table>
<context>We’re in the middle of something</context> <- my heading
<table>data</table>
Thanks to Daniel Haley I was able to find a solution for that problem. I'll post it here, so it is independend of the pastebin I postet below.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:v="urn:schemas-microsoft-com:vml" exclude-result-prefixes="xsl w v">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="w:tbl">
<context>
<xsl:value-of select="(preceding-sibling::w:p[w:pPr/w:pStyle[#w:val = 'berschrift1']])[last()]"/>
</context>
<table>
<xsl:value-of select="."/>
</table>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Hard to answer without a Minimal, Complete, and Verifiable example, but try this:
<xsl:template match="w:tbl">
<p>
<table>
<xsl:value-of select="(preceding::w:p[w:pPr/w:pStyle[#w:val='berschrift1']])[last()]"/>
</table>
</p>
</xsl:template>
Assuming you can use XSLT 2.0 (and most people can, nowadays), I find a useful technique here is to have a global variable that selects all the relevant nodes:
<xsl:variable name="special"
select="//w:tbl/preceding-sibling::w:p[w:pPr/w:pStyle[#w:val='berschrift1']][1]"/>
and then use this variable in a template rule:
<xsl:template match="w:p[. intersect $special]"/>
In XSLT 3.0 you can reduce this to
<xsl:template match="$special"/>
I have following XML input:
<table>
<tbody>
<tr>
<td style="width: 10px; margin-left: 10px;">td text</td>
<td style="color: red; width: 25px; text-align: center; margin-left: 10px;">
<span>span text</span>
</td>
</tr>
</tbody>
</table>
Please note that I have other nodes in the same document that should not be touched.
I want to remove certain attribute values from an element (in this case from td).
Let's say I want to remove the width value within a style attribute.
I don't know where in the style-attribute the width-value is set, it could be anywhere.
The span in the td doesn't really matter (this and some other elements are there in the input).
I expect the output to be like this:
<table>
<tbody>
<tr>
<td style="margin-left: 10px;">td text</td>
<td style="color: red; text-align: center; margin-left: 10px;">
<span>span text</span>
</td>
</tr>
</tbody>
</table>
I prefer using XSLT1, I did not bring the replace() function to work yet (but maybe I am doing something wrong).
I tried using this XSLT:
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="td/#style">
<xsl:attribute name="style">
<xsl:value-of select="replace(., 'width:.[[:digit:]]+px;', '')" />
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:template>
I am still a beginner in XSLT and this above doesn't work and I did not find a solution here.
Also, I don't know the width-value so I would need to replace the value with a regex (I used "width:.[[:digit:]]+px;") or something.
Is there maybe a easier method that can replace every specific value? So I could remove text-align aswell without having to think of a new regex?
I really hope that you can help me with this (surely easy) problem.
Thank you in advance!
Let's say I want to remove the width value within a style attribute. I
don't know where in the style-attribute the width-value is set, it
could be anywhere.
Try:
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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="td/#style[contains(., 'width:')]">
<xsl:attribute name="style">
<xsl:value-of select="substring-before(., 'width:')" />
<xsl:value-of select="substring-after(substring-after(., 'width:'), ';')" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Note:
I want to remove certain attribute values from an element (in this
case from td).
Actually, what you want is to remove certain properties from the style attribute. The above will work for removing a single property; if you want to remove more than one, you'll have to use a recursive template to do it.
Added:
Will there be an issue if the style contains border-width:1px as
this become border-?
Yes, this could be a problem. A possible solution would be:
<xsl:template match="td/#style">
<xsl:variable name="style" select="concat(' ', .)" />
<xsl:choose>
<xsl:when test="contains($style, ' width:')">
<xsl:attribute name="style">
<xsl:value-of select="substring-before($style, ' width:')" />
<xsl:value-of select="substring-after(substring-after($style, ' width:'), ';')" />
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
However, this assumes that the ; separator in the source document is always followed by a space (as it is in the given example). Otherwise it gets more complicated.
Assuming you are using XSLT 2.0 (as replace is not supported in 1.0) you can use \d to match a digit in regular expressions, so you can write your pattern like so:
<xsl:value-of select="replace(., '( | $)width:\s*\d*px;?', '')" />
Note the \s* is used to match zero or more characters of whitespace, so allow for width:10px or width: 10px. Also not ( | $) is used to ensure a space before width (or if it is at the start), so that properties like border-width are not matched.
If you wanted to handle units other than px you could do this...
<xsl:value-of select="replace(., '( | $)width:[^;]+;?', '')" />
Read up on regular expressions at http://www.xml.com/pub/a/2003/06/04/tr.html.
I'm trying to display a series of images each with its own caption using XSLT. I've coded the images and the captions by nesting <img> and then <figcaption> within but the resultant html does not display as intended (the captions are not lining up with corresponding images). Is there a way to nest <xsl: for-each> for the captions within the images? Here's the XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xlink="http://www.w3.org/1999/xlink"
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:output method="html"/>
<xsl:template match="letter">
<html>
<head>
<style type="text/css">
#wrapper {min-height: 100%;}
#figcaption {
text-align: left;
}
#main {
padding-top: 15px;;
width: 1200px;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="images">
<figure>
<xsl:if test="image">
<xsl:for-each select="image/#xlink:href">
<img>
<xsl:attribute name="src">
<xsl:value-of select="."/>
</xsl:attribute>
</img>
</xsl:for-each>
</xsl:if>
<xsl:if test="image/#label">
<xsl:for-each select="image/#label">
<figcaption><xsl:value-of select="."/></figcaption>
</xsl:for-each>
</xsl:if>
</figure>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Here's the corresponding XML:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="XSLT.xsl"?>
<letter xmlns:xlink="http://www.w3.org/1999/xlink">
<image label="page 1" xlink:href="http://tinyurl.com/nu7zmhc"/>
<image label="page 2" xlink:href="http://tinyurl.com/pysyztr"/>
<title>Letter from Shawn Schuyler</title>
<date>1963-06-30</date>
<language>English</language>
<creator>
<firstName>William</firstName>
<lastName>Schultz</lastName>
<street>Unites States Disciplinary Barracks</street>
<city>Fort Leavenworth</city>
<state abbr="KS">Kansas</state>
</creator>
</letter>
My desired output in html is basically this for each image:
<figure>
<img src='image.jpg'/>
<figcaption>Caption</figcaption>
</figure>
Or simply:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink"
exclude-result-prefixes="xlink">
<xsl:template match="/letter">
<html>
<head>
<style type="text/css">
#wrapper {min-height: 100%;}
#figcaption {
text-align: left;
}
#main {
padding-top: 15px;;
width: 1200px;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="images">
<xsl:for-each select="image">
<figure>
<img src='{#xlink:href}'/>
<figcaption>
<xsl:value-of select="#label"/>
</figcaption>
</figure>
</xsl:for-each>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Note:
There's nothing wrong with using xsl:for-each, especially in a
simple case like this;
There is something wrong with using xsl:element when you can use a literal result element. And while XSLT is naturally verbose, using the attribute value template can reduce the code (quite significanltly, as you can see in this case).
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xlink="http://www.w3.org/1999/xlink"
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:output method="html" indent="yes" />
<xsl:template match="letter">
<html>
<head>
<style type="text/css">
#wrapper {min-height: 100%;}
#figcaption {
text-align: left;
}
#main {
padding-top: 15px;;
width: 1200px;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="images">
<xsl:apply-templates select="./image"></xsl:apply-templates>
</div>
</div>
</body>
</html>
</xsl:template>
<xsl:template match="letter/image">
<xsl:element name="figure">
<xsl:element name="img">
<xsl:attribute name="src">
<xsl:value-of select="./#xlink:href"/>
</xsl:attribute>
</xsl:element>
<xsl:apply-templates select="./#label"></xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="letter/image/#label">
<xsl:element name="figcaption">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
xsl:apply-templates says where anything matching the pattern specified in select should be put (with the dot showing the current element's context).
xsl:template is matched against the source document based on the path given in match. Any hits are processed in parallel, then later stitched together based on where the apply-templates elements indicate.
NB: depending on your XSLT engine having output="html" may have different effects on your img element. In HTML5 the img element is defined as not requiring a close tag (or being self-closing), so the engine won't close that tag. Arguments about whether that inconsistency is a good choice or not can be found throughout the net.
Ref: Are (non-void) self-closing tags valid in HTML5?
A good article on this alternate approach to for-each can be found here: http://gregbee.ch/blog/using-xsl-for-each-is-almost-always-wrong
You'll find with XLST that once the concept of a template clicks your code will become way shorter are simpler to maintain.
i would like to create a master template in XSLT, which could be stored in a separate file. Every other Page stylesheets share it, with xsl:import.
master.xslt
<xsl:template match="Page">
<html>
<head>
</head>
<body>
<call-template name="Content"/>
</body>
</html>
</xsl:template>
<xsl:stylesheet>
page.xslt
<xsl:stylesheet>
<xsl:import href="master.xslt"/>
<xsl:template match="/">
<apply-templates match="Page"/>
</xsl:template>
<xsl:template name="Content">
... apply something page-specific
</xsl:template>
</xsl:stylesheet>
page.xml
<Page>
... something page-specific
</Page>
Can i improve this solution?
i cannot start from master stylesheet, because i will need xsl:import everything.
i dont want master.xslt contain references on each particular page.
Another decision (which is against the xslt spirit) maybe such:
master.xslt
<xsl:template name="masterHead">
<html>
<head>
</head>
<body>
</xsl:template>
<xsl:template name=masterEnd>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
page.xslt
<xsl:stylesheet>
<xsl:import href="master.xslt"/>
<xsl:template match="/">
<call-template name=masterHead>
... apply something page-specific
<call-template name=masterEnd/>
</xsl:template>
</xsl:stylesheet>
we don't need any general root <Page> element.
Using <xsl:import> is the right design decision. This is exactly the main use-case this XSLT directive was intended for.
One can go further even more -- lookup for the <xsl:apply-imports> directive, and in addition to how an imported stylesheet can apply templates about whose actions and meaning it absolutely doesn't know anything. The latter is called Higher-Order-Functions and is implemented in XSLT with the FXSL library (written entirely in XSLT).
That looks about right to me... very common to what I have used in the past (although I've often used <xsl:include/>, but either should work). The main change I might make is to make the match more explicit (at least in the master xslt) - i.e.
<xsl:template match="/Page"> <!-- leading slash -->
so it won't accidentally match Page elements at other locations (for example, data-paging, like <Page Index="3" Size="20"/>).
One other common thing I do is to add a "*" match that uses xsl:message to throw an error if I don't have a more-specific match for a node. This makes it more obvious when you have a typo, etc.
I'm actually glad to have found this example as I've been looking for verification that this is actually the correct approach to a master/slave template setup.
However the examples provided did not work out of the box on tomcat - so just to help others who only knows how to copy paste here are a working tomcat set of master / slave files.
Master.xsl :
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="iso-8859-15" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" indent="no"/>
<!-- http://stackoverflow.com/questions/646878/master-stylesheet-sharing-in-xslt -->
<xsl:template match="ms247">
<html>
<head>
<title>test</title>
</head>
<body>
<div style="border: 1px solid black; width: 200px; float: left; margin: 10px; padding: 5px;">
<xsl:call-template name="left"/>
</div>
<div style="border: 1px solid black; width: 200px; float: left; margin: 10px; padding: 5px;">
<xsl:call-template name="content"/>
</div>
<div style="border: 1px solid black; width: 200px; float: left; margin: 10px; padding: 5px;">
<xsl:call-template name="right"/>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="content">
<span style="color: red">Content template is empty - overrule in page template.</span>
</xsl:template>
<xsl:template name="left">
<span style="color: red">Left template is empty - overrule in page template.</span>
</xsl:template>
<xsl:template name="right">
<span style="color: red">Right template is empty - overrule in page template.</span>
</xsl:template>
</xsl:stylesheet>
And slave.xsl:
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="master.xsl"/>
<xsl:template name="content">
... apply something page-specific
</xsl:template>
<xsl:template name="right">
And we have RIGHT content!
<!-- Execute matching template which is NOT triggered automatically -->
<xsl:apply-templates select="params/param"/>
</xsl:template>
<!-- And we do not define any left template -->
<!-- Example -->
<xsl:template match="ms247/params/param">
Paramters on page: <xsl:value-of select="#name"/><br/>
</xsl:template>
</xsl:stylesheet>
Hope this can help others - do not be shy to drop me a note.