I'm starting using XSLT and write this scipt:
<?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="text" encoding="utf-8" />
<xsl:template match="span[#class='thumb']" >
Link: <xsl:value-of select="$base" /><xsl:value-of select="a/#href" />
</xsl:template>
<xsl:template match="/">
Base href: <xsl:value-of select="$base" />
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
And using this command:
xsltproc --html --param base "'http://example.com'" lista.xslt test.html
I need to get list of Links, but I get whole page on output. What's wrong? How can I get it works?
There are some default templates which are unseen here. The really easy way to resolve it is to just explicitly limit to the span elements you're matching as below. Otherwise, you can override the default templates.
<xsl:template match="/">
Base href: <xsl:value-of select="$base" />
<xsl:apply-templates select="//span[#class='thumb']" />
</xsl:template>
There's a default template that matches essentially everything if you let it. Your 4th last line calls that template.
That's part of the problem. The rest can probably be taking care of by matching just the stuff you're looking for, directly in the top-level template.
Related
I have XML that has encoded HTML data. I am trying to render the data but can't seem to figure out how. Best I can tell is I need to disable-output-escaping="yes" twice but not sure how to do that.
For example, this is a snippet of my XML:
<root>
<node value="<b>body</b>" />
</root>
My XSLT is outputting HTML. Here is the rendered output (the HTML source) with various options
<xsl:value-of select="#value" /> outputs <b>hi</b>
<xsl:value-of select="#value" disable-output-escaping="yes" /> outputs <b>hi</b>
I would like it to output <b>hi</b> to the HTML source so its actually rendered as a bolded hi. Does that make sense? Is that possible?
Escaping is the process of turning < into <. If you disable escaping, it will leave < as <. What you want to achieve is to turn < into <, which would normally be called "unescaping".
In the normal course of events, a parser performs unescaping, while a serializer performs escaping. So if you want to unescape characters, you need to put them through a parsing process, which means you need to take the content of the #value attribute and put it through an operation like fn:parse-xml-fragment() in XPath 3.0, or an equivalent extension function in your chosen processor.
Assuming Sharepoint as a Microsoft .NET product uses XslCompiledTransform you could try to implement the unescaping and parsing with extension "script" (C# or VB or JScript.NET code embedded in XSLT) as follows:
<?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"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="msxsl mf">
<msxsl:script language="C#" implements-prefix="mf">
<msxsl:using namespace="System.IO"/>
public string Unescape(string input)
{
XmlDocument doc = new XmlDocument();
XmlDocumentFragment frag = doc.CreateDocumentFragment();
frag.InnerXml = input;
return frag.InnerText;
}
public XPathNavigator ParseXml(string xmlInput)
{
using (StringReader sr = new StringReader(xmlInput))
{
return new XPathDocument(sr).CreateNavigator();
}
}
</msxsl:script>
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node">
<div>
<xsl:copy-of select="mf:ParseXml(mf:Unescape(#value))" />
</div>
</xsl:template>
</xsl:stylesheet>
If you have access to an XSLT processor (like any version of Saxon 9.7 or Exselt or the latest Altova or XmlPrime) supporting the XPath 3 functions parse-xml and parse-xml-fragment you can write that template without extension functions (in a version="3.0" stylesheet) as
<xsl:template match="node">
<div>
<xsl:copy-of select="parse-xml(string(parse-xml-fragment(#value)))"/>
</div>
</xsl:template>
Output your result with disable-output-escaping, then treat it again in another XSL with disable-output-escaping.
I have a variable containing non-numerical values, and I need to completely remove duplicate entries from this string using XSLT:
$string = a,b,c,c,d,d,e,f,g
needs to become: $newstring = a,b,e,f,g
An alternative option would be to compare the two variables and ignore/remove the overlapping entries.
$stringA = a,c
$stringB = a,b,c,d,e,f
needs to become:
$newstring = b,d,e,f
Concatenating the variables is straightforward but I need the opposite of that!
Please help,
XSLT is designed to process XML, not strings. XSLT 1.0 in particular is a poor tool for manipulating text.
IMHO, the best way to proceed here is to convert the problem to XML first. If you're using libxslt (as xsltproc does), this is quite easy to do using an extension function:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="stringA">a,c,g</xsl:param>
<xsl:param name="stringB">a,b,c,d,e,f</xsl:param>
<xsl:variable name="setA" select="str:tokenize($stringA, ',')" />
<xsl:variable name="setB" select="str:tokenize($stringB, ',')" />
<xsl:template match="/">
<test>
<xsl:for-each select="$setA[not(.=$setB)] | $setB[not(.=$setA)]">
<xsl:value-of select="."/>
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each>
</test>
</xsl:template>
</xsl:stylesheet>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<test>g,b,d,e,f</test>
Here is my setup:
<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:include href="top.xsl"/>
<xsl:template match="">
Content here - divs and such
</xsl:template>
</xsl:transform>
Then this is the stylesheet that I am trying to include.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
Standard html file now, html, head,title,script,body etc.
Closes like this:
<xsl:apply-templates />
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Why won't the include work?
Edit: Here is the full code: https://gist.github.com/anonymous/3432742335a8fd3c600f
When you do <xsl:apply-templates /> in your nav.xsl this will look for child nodes of the document node. As XML needs a single root element to be well-formed, you can replace your currently empty template match with this to match this root element
<xsl:template match="/*" >
How to modify the below xsl to process parameters whose value is tags. Instead of using w:p and w:pPr/w:pStyle/#w:val i will be passing them as args
Actual XSl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
>
<xsl:param name="styleName"/>
<xsl:output method="text"/>
<xsl:template match="w:p"/>
<xsl:template match="w:p[w:pPr/w:pStyle/#w:val[matches(., concat('^(',$styleName,')$'),'i')]]">
<xsl:value-of select="."/><xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Required XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<xsl:param name="styleName" select="'articletitle'"/>
<xsl:param name="para" select="'//w:p[w:pPr/w:pStyle/#w:val[matches(.,concat('^(',$styleName,')$')]]'"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="$para">
<xsl:value-of select="."/><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
NOTE: You should get used to give information about which version of xslt and which processor you are using. In this case, the answer is valid only if you are using XSLT 2.0
This is not a complete answer, but you can start by looking at this approach:
Try using local-name and in-scope-prefixes (only available in XSLT 2.0) to match a node dynamically.
Here you have an example template to replace your empty template:
<xsl:template match="*[local-name()=substring-after($para,':') and in-scope-prefixes(.)[.=substring-before($para,':')]]"/>
For the second part of the expression ($parastyle), I can only think about writing your own function to evaluate it dynamically.
I'll try to post an example of such a function later on.
I fugured out the problem in my coding, is in second line,
<xsl:param name="para" select="'//w:p[w:pPr/w:pStyle/#w:val[matches(.,concat('^(',$styleName,')$')]]'"/>
Since i have given the quotes in select attribute the value has been considered as string instead of xpath expression.
I want to match mulitple values of a attribute for replacing. for example
<div class="div h1 full-width"></div>
Should produces div, h1 and full-width as seperate matches.
I want to do this to prefix the classes. So instead of div h1 full-width it should be pre-div pre-h1 pre-full-width
The regex I have sofar is
(?<=class=["'])(\b-?[_a-zA-Z]+[_a-zA-Z0-9-]*\b)+
This matches only the first class. This is offcourse because that is the only thing this pattern should match :( I tried to make the lookbehind take more then just class=" but I just end up with it taking everying and leaving nothing to replace.
I want to make a pattern that matches any value individually between the quotes of the class attribute.
I want to do this for an Ant buildscript that processes all files and replaces the class="value1 value2 value3" with a set prefix. Ive done this with little trouble for replacing the classes in css files but ye html seems to be alot trickier.
It is a Ant buildscript. Java regexp package is used to process the pattern. The ant tag used is: replaceregexp
The ant implemtentation of above pattern is:
<target name="prefix-class" depends="">
<replaceregexp flags="g">
<regexp pattern="(?<=class=['"])(\b-?[_a-zA-Z]+[_a-zA-Z0-9-]*\b)+"/>
<substitution expression=".${prefix}\1"/>
<fileset dir="${dest}"/>
</replaceregexp>
</target>
I don't think that you can find n (or in your case 3) different class entries and substitude them in one simple regexp. If you need to do this in ant i think you have to write your own ant task. A better way would be xslt, are you familiar with xslt?
Gave up on Ants ReplaceRegExp and sorted my problem with XSLT to transform xhtml to xhtml.
Following code adds a prefix to all values of a elements class attribute. the xhtml source document must be properly formatted to be parsed.
<xsl:stylesheet version="2.0"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xhtml xsl xs">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd"
indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="prefix" select="'oo-'"/>
<xsl:template match="/">
<xsl:apply-templates select="./#*|./node()" />
</xsl:template>
<!--remove these atts from output, default xhtml values from dtd -->
<xsl:template match="xhtml:a/#shape"/>
<xsl:template match="#rowspan"/>
<xsl:template match="#colspan"/>
<xsl:template match="#class">
<xsl:variable name="replace_regex">
<xsl:value-of select="$prefix"/>
<xsl:text>$1</xsl:text>
</xsl:variable>
<xsl:attribute name="class">
<xsl:value-of select="fn:replace( . , '(\w+)' , $replace_regex )"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>