I have a big set of XSLT templates that generate <div> elements with assorted content. Matches look like these:
<xsl:template match="block[#name = 'block_blah']">
<div>
blah
<div>foooo</div>
</div>
</xsl:template>
<xsl:template match="block[#name = 'block2']">
<div>
<div>xyz</div>
abc
</div>
</xsl:template>
I need to add an attribute to every first level <div>. So the output will become:
<div data-blockname="block_blah">
blah
<div>foooo</div>
</div>
<div data-blockname="block2">
<div>xyz</div>
abc
</div>
Do I have to insert data-blockname="{#name}" manually in every case? Or is there a way to inject it globally?
There is no way to do this "globally" as you say, but there are ways to restructure your XSLT and avoid repetition, like this:
<xsl:template match="block[#name]">
<div name="{#name}">
<xsl:apply-templates select="." mode="content" />
</div>
<xsl:template>
<xsl:template match="block[#name = 'block_blah']" mode="content">
blah
<div>foooo</div>
</xsl:template>
<xsl:template match="block[#name = 'block2']" mode="content">
<div>xyz</div>
abc
</xsl:template>
Related
I need to remove the child element on the bases of the value of an id attribute. If there is no value in id attribute or there is no id attribute at all in contentblock tag then just remove the element and parent element will remain same if present. Also if content block is direct child of root and that content block doesn't have value in id attribute or there is no id attribute then remove that element also.
Example:
<root>
<div>
<contentblock class="align-center" id="" />
</div>
<p>
<contentblock class="align-center" />
</p>
<h2>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
</h2>
<contentblock class="align-center" id=""/>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
<contentblock class="align-center"/>
</root>
Expected Result:
<root>
<div>
</div>
<p>
</p>
<h2>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
</h2>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
</root>
Thanks in advance for the help.
What i tried but didn't give the expected result:
<!--<xsl:template match="contentblock[not(parent::root)] | contentblock[(parent::root)]">-->
<!--<xsl:choose>-->
<!-- <xsl:if test="contentblock/#id[string-length(.) =0]">-->
<!-- <xsl:apply-templates/>-->
<!-- </xsl:if>-->
<!--</xsl:choose>-->
<!--</xsl:template>-->
Another try:
<xsl:template match="div[contentblock] | p[descendant::contentblock] | h2[descendant::contentblock] | h3[descendant::contentblock]">
<xsl:choose>
<xsl:when test="contentblock[#id!='']">
<xsl:apply-templates/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="contentblock[#id=''] | contentblock[not(#id)]">
<xsl:copy> <xsl:apply-templates select="#*"/></xsl:copy>
</xsl:when>
</xsl:choose>
</xsl:template>
I can't match <xsl:template match="contentblock[not(parent::root)]"> as it performs the transformation on content block element itself which gives me different result. And also above solution does not work when i get the xml like this. When contentblock have multiple level parents like here it's p and span are parents of contentblock.
<p id="5c3692c8af8fe1f061518abc">
<span bulb-font-face="museo-sans, sans-serif">
<contentblock class="align-center block-full-width" id="5c3686fdcb7de304cd51696f" />
</span>
</p>
This template would match contentblock elements with an id attribute that has some value:
<xsl:template match="contentblock[#id!='']"/>
You would have to apply this template to all relevant contentblock elements, and in the template you would have to return whatever you want to return, like
<xsl:copy-of select="."/>
I have some data that i put in (image, title, text). I ahve 3 different elements in my xslt for each of them:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:udt="DotNetNuke/UserDefinedTable" exclude-result-prefixes="udt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<!--
This prefix is used to generate module specific query strings
Each querystring or form value that starts with udt_{ModuleId}_param
will be added as parameter starting with param
-->
<xsl:variable name="prefix_param">udt_<xsl:value-of select="//udt:Context/udt:ModuleId" />_param</xsl:variable>
<xsl:template match="udt:Data" mode="list">
<xsl:value-of select="udt:Image" disable-output-escaping="yes" />
<xsl:value-of select="udt:Title" disable-output-escaping="yes" />
<xsl:value-of select="udt:Text" disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="/udt:UserDefinedTable">
<xsl:variable name="currentData" select="udt:Data" />
<xsl:if test="$currentData">
<xsl:apply-templates select="$currentData" mode="list">
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template name="EditLink">
<xsl:if test="udt:EditLink">
<a href="{udt:EditLink}">
<img border="0" alt="edit" src="{//udt:Context/udt:ApplicationPath}/images/edit.gif" />
</a>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I want to fill these elements each into its own div group, so my end result would be something like this:
<div id="images">
<!--all images here-->
</div>
<div id="title">
<!--all titles here-->
</div>
<div id="text">
<!--all texts here-->
</div>
Can this be achieved by any kind of grouping or whats the right aproach?
The concept to use xsl:value-of for your 3 element types is wrong,
as this instruction copies only the content of these elements,
without XML markup.
Assuming that the only goal is to reorder (group) your elements,
and they are direct descendants of the current element (udt:Data),
the task can be done the following way:
<xsl:template match="udt:Data">
<xsl:copy>
<div id="images">
<xsl:copy-of select="udt:Image"/>
</div>
<div id="title">
<xsl:copy-of select="udt:Title"/>
</div>
<div id="text">
<xsl:copy-of select="udt:Text"/>
</div>
</xsl:copy>
</xsl:template>
Of course, this is only a template, not the whole script.
Note that e.g. if these elements were located also at "deeper" descendant levels,
all the above XPath expressions should be prececed with descendant::.
And remember about including in your script all namespaces, the script refers to.
They should be declared in stylesheet tag.
I'm learning to use the mode attribute and must being doing something wrong. Apologies if this has been answered before but I'm not finding it here.
I want to process "title" elements separately depending on their context. For the main document, I want to add an "a" element inside of it:
<xsl:template match="title">
<div>
<xsl:value-of select="."/>
<a href="some_URL">some text
</a>
</div>
</xsl:template>
But elsewhere I'm creating result-documents where I just want the title:
<xsl:tamplate match="title" mode="print">
<div class="title">
<xsl:value-of select="."/>
</div>
</xsl:template>
In my main template match="/" I'm doing a for-each for each section, creating a result-document for each one:
<xsl:for-each select="/topic/body/bodydiv/section">
<xsl:result-document href="{$printoutfile}">
<html><head>some stuff</head><body>
<div class="section">
<xsl:apply-templates mode="print"/>
</div>
... more stuff...
</body</html>
</xsl:result-document>
</xsl:for-each>
Then I call everything else for the main document:
<html><head>stuff</head>
<body>
<div>
<xsl:apply-templates/>
</div>
</body>
</html>
The problem is this works for the result-document title but none of the rest of the result-document templates are used, since they don't have mode="print" on them. So the rest of the result-document all comes out as text.
Any idea what I need to do here? I'm obviously missing something basic.
thank you
Scott
You have not shown any of the other templates but if you expect the <xsl:apply-templates mode="print"/> to apply them then you need to have a mode="#all" on them. And if they do additional apply-templates then you need to use <xsl:apply-templates select="#current"/>. See http://www.w3.org/TR/xslt20/#modes for details.
I am transforming xml to html using saxon.
I have xml like this:
<abc>
level-1
<abc>
level-2
<abc>
level-x
</abc>
</abc>
</abc>
in html i want to do something like this:
<div class="abc-1">
level-1
<div class="abc-2">
level-2
<div class="abc-3">
level-3
</div>
</div>
</div>
Now in my xslt i want to do somthing like following, so i can have different class names in child node with same node match, but not sure what could be good and optimized way to do this in xslt.
<xsl:template match = "abc">
<div class="abc<x>">
<xsl:apply-templates />
</div>
</xsl:template>
<xsl:template match="abc">
<div class="abc-{count(ancestor-or-self::abc)}">
<xsl:apply-templates />
</div>
</xsl:template>
I have the following XML
<title>
This is a <highlight>test</highlight> thanks.
</title>
and want to convert into
<span class="title">this is a <span class="highlight">test</span> thanks.</span>
I try this xslt, only can ge the text inside title tag, how can I also convert the highlight tag?
<span class="title"><xsl:value-of select="title"/></span>
<xsl:template match="title">
<span class="title">
<xsl:apply-templates />
</span>
</xsl:template>
<xsl:template match="highlight">
<span class="highlight">
<xsl:apply-templates />
</span>
</xsl:template>
or, if you want, collapse it into a single template:
<xsl:template match="title|highlight">
<span class="{name()}">
<xsl:apply-templates />
</span>
</xsl:template>
Key point is the <xsl:apply-templates /> - it runs all child nodes of the current node through the appropriate templates. In the upper variant, the appropriate templates are separate, in the lower variant the one template is called recursively.
There is a default rule defined in XSLT that copies text nodes. All text is run through this rule by <apply-templates>, so text nodes appear in the output autmatically.
Use xsl:copy-of instead of xsl:value-of if you want a full copy of the node and all of its children:
<span class="title"><xsl:copy-of select="title"/></span>
But for what you are trying to do, I would create one template for the title element and one for the highlight element:
<xsl:template match="title">
<span class="title"><xsl:value-of select="." /></span>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="highlight">
<span class="highlight"><xsl:value-of select="." /></span>
</xsl:template>