xsl want to transform the following xml to html: - xslt

<!ELEMENT TITLE (CDATA | ELEMENTX )+ >
If I use the below then when
TITLE contains CDATA and
ELEMENTX contains CDATA I get duplicate text.
How should a template for this element TITLE be written?
<xsl:template match="TITLE">
<span>
<p><xsl:value-of select="."/></p>
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="local-name()='ELEMENT1'">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</span>
</xsl:template>

As per my understanding, it seems that you are stuck when mixed type of content allowed in DTD, and you are handling when CDATA appear and face issue if there is further child elements.
If you are suppose to push all child inside p then you can use <xsl:apply-templates/>
and handle further data in template.
If you only require for handle your code for CDATA updation then use
<p>
<xsl:if test="text()">
<xsl:value-of select="text()"/>
</xsl:if>
</p>
instead of
<p><xsl:value-of select="."/></p>

The following seems to do exactly what I need.
It puts out the Text from the parent element TITLE if any before any child element. Then it works on a child element if any and then puts out any text in the parent before the next child and so on.
<xsl:template match="TITLE">
<span>
<xsl:for-each select="* | ./text()">
<xsl:choose>
<xsl:when test="local-name()=''">
<xsl:value-of select="."/>
</xsl:when>
<xsl:when test="local-name()='ELEMENT1'">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</span>
</xsl:template>

Related

XSL Using replace and matches to update values

I am trying to update an old form that uses a data model that has changed, so any reference to the old model I want to replace with the new. I currently use the function matches to tell if I should preform the replace on the current string and then use the replace function to replace the value with the new one, the problem is that the regex used in the matches does not work with the regex in the replace.
<xsl:template
match="//*[contains(#*:default,'instance(''document'')/')
mode="pass">
<xsl:variable
name="regex"
as="element()*">
<regex>instance('document')/doc_type/description</regex>
<regex>anotherRegex</regex>
</xsl:variable>
<xsl:variable
name="replacement"
as="element()*">
<replacement>xxf:get-request-parameter('documentDesc')</replacement>
<replacement>replacedRegex</replacement>
</xsl:variable>
<xsl:element name="{name()}">
<xsl:for-each select="#*">
<xsl:choose>
<xsl:when test="name() = ('xxf:default')">
<xsl:attribute name="xxf:default">
<xsl:analyze-string
regex="{concat('(',$regex[1],'|',$regex[2],')')}"
select=".">
<xsl:matching-substring>
<xsl:if test="matches(.,$regex[1])">
<xsl:value-of select="replace(.,$regex[1],$replacement[1])" />
</xsl:if>
<xsl:if test="matches(.,$regex[2])">
<xsl:value-of select="replace(.,$regex[2],$replacement[2])" />
</xsl:if>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="{local-name()}"><xsl:value-of select="." /></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:template>
Current XML:
<xf:bind id="clinic-bind"
name="clinic"
xxf:default="instance('document')/doc_type/description"
type="xf:string"/>
What I want to turn it into:
<xf:bind id="clinic-bind"
name="clinic"
xxf:default="xxf:get-request-parameter('documentDesc')"
type="xf:string"/>
So the Problem was basicaally I had to escape the '()' characters in the regex variable.
So I ended up with
<regex>instance\('document'\)/doc_type/description</regex>
In the regex part.

Numbered bookmarks in PDF output from DITA bookmaps with and without parts

I am trying to create PDF output with numbered headings using the DITA OT and a custom plugin. By default, the output contains part numbers, chapter numbers and appendix number in the headings and the TOC, but no numbers in the bookmarks. So far, I have managed to number all the remaining topics in the headings and the TOC, like so (the chapter numbers restart in every part):
bookmap
part I
chapter 1
topic 1.1
topic 1.2
chapter 2
part II
chapter 1
However, I cannot get the same numbers for the bookmarks.
I am using the following code (or override) to select the bookmarks that must be numbered:
<xsl:template match="*[contains(#class, ' topic/topic ')]" mode="bookmark">
<xsl:variable name="mapTopicref" select="key('map-id', #id)[1]"/>
<xsl:variable name="topicTitle">
<xsl:call-template name="getNavTitle"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$mapTopicref[#toc = 'yes' or not(#toc)] or
not($mapTopicref)">
<fo:bookmark>
<xsl:attribute name="internal-destination">
<xsl:call-template name="generate-toc-id"/>
</xsl:attribute>
<xsl:if test="$bookmarkStyle!='EXPANDED'">
<xsl:attribute name="starting-state">hide</xsl:attribute>
</xsl:if>
<fo:bookmark-title>
<xsl:choose>
<xsl:when test="contains($mapTopicref/#class, ' bookmap/part ')">
<xsl:call-template name="getChapterPrefix"/>
<xsl:text> </xsl:text>
</xsl:when>
<xsl:when test="contains($mapTopicref/#class, ' bookmap/appendix ')">
<xsl:call-template name="getChapterPrefix"/>
<xsl:text> </xsl:text>
</xsl:when>
<xsl:when test="contains($mapTopicref/#class, ' bookmap/chapter ')">
<xsl:call-template name="getChapterPrefix"/>
<xsl:text> </xsl:text>
</xsl:when>
</xsl:choose>
<xsl:value-of select="normalize-space($topicTitle)"/>
</fo:bookmark-title>
<xsl:apply-templates mode="bookmark"/>
</fo:bookmark>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates mode="bookmark"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I am using the following code to create the numbers (derived from an example in DITA for Print):
<xsl:template name="getChapterPrefix">
<xsl:variable name="topicType">
<xsl:call-template name="determineTopicType"/>
</xsl:variable>
<xsl:variable name="partsCount">
<xsl:value-of select="count($map//*[contains(#class, ' bookmap/part')])"/>
</xsl:variable>
<xsl:variable name="containingChapter" select="ancestor-or-self::*[contains(#class, ' topic/topic')][position()=1]"/>
<xsl:variable name="id" select="$containingChapter/#id"/>
<xsl:variable name="topicChapters">
<xsl:copy-of select="$map//*[contains(#class, ' bookmap/chapter')]"/>
</xsl:variable>
<xsl:variable name="topicAppendices">
<xsl:copy-of select="$map//*[contains(#class, ' bookmap/appendix')]"/>
</xsl:variable>
<xsl:variable name="topicParts">
<xsl:copy-of select="$map//*[contains(#class, ' bookmap/part')]"/>
</xsl:variable>
<xsl:variable name="chapterNumber">
<xsl:choose>
<xsl:when test="$topicChapters/*[#id = $id]">
<xsl:choose>
<xsl:when test="$partsCount=0"> <!-- Bookmaps without parts work fine -->
<xsl:number format="1" value="count($topicChapters/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:otherwise> <!-- This does not work yet. -->
<xsl:number format="1" value="count($topicChapters/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$topicAppendices/*[#id = $id]">
<xsl:number format="A" value="count($topicAppendices/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:when test="$topicParts/*[#id = $id]">
<xsl:number format="I" value="count($topicParts/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$chapterNumber != ''">
<xsl:value-of select="$chapterNumber"/>
</xsl:when>
</xsl:choose>
</xsl:template>
With this code, parts, appendices and bookmaps without parts are numbered correctly. However, for bookmaps with parts, chapters are numbered consecutively, which is inconsistent.
bookmap
part I
chapter 1
topic 1.1
topic 1.2
chapter 2
part II
chapter 3
Can anybody help me to correct this?
I just found a way to obtain the result I want. The piece of code that calculates the chapter number for bookmaps with parts was modified als follows:
<!-- If there's something in $topicChapters with an id that matches the id of the
context node, then I'm inside a chapter. -->
<xsl:when test="$topicChapters/*[#id = $id]">
<xsl:choose>
<xsl:when test="$partsCount=0"> <!-- Bookmaps without parts -->
<xsl:number format="1" value="count($topicChapters/*[#id =$id]/preceding-sibling::*) + 1"/>
</xsl:when>
<xsl:otherwise> <!-- Bookmaps with parts. -->
<xsl:number format="1" value="count(//*[contains(#class,' bookmap/chapter ')][#id =$id]/preceding-sibling::*)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
This is probably everything but elegant, but then, I'm a tech writer ...

In MathML, how to remove particular element based on its parent and its parent position?

Please help me to find the mmlmsubsup's third child starts with mmlmi with attribute.
Find the XML given below, suggest to remove the particular element based on its position and parent.
<article><mmlmath><mmlmsubsup><mmlmrow><mmlmi>A</mmlmi></mmlmrow><mmlmrow><mmlmi>b</mmlmi></mmlmrow><mmlmrow><mmlmi mathcolor="magenta">#</mmlmi><mmlmo>(</mmlmo><mmlmo>c</mmlmo><mmlmo>)</mmlmo></mmlmrow></mmlmsubsup></mmlmath></article>
SubSup.xslt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="mmlmsubsup">
<mmlmsubsup>
<xsl:for-each select="child::*[1]">
<xsl:choose>
<xsl:when test="child::*[1][name()='mmlmrow']">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:when>
<xsl:otherwise><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="child::*[2]">
<xsl:choose>
<xsl:when test="child::*[1][name()='mmlmrow']">
<xsl:for-each select="mmlmrow">
<xsl:if test="child::*[1][name()='mmlmi'][#mathcolor]">delete</xsl:if>
<xsl:if test="not(child::*[name()='mmlmi'][#mathcolor])"><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:if>
</xsl:for-each>
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:when>
<xsl:otherwise><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="child::*[3]">
<xsl:choose>
<xsl:when test="child::*[1][name()='mmlmrow']">
<xsl:for-each select="mmlmrow">
<xsl:if test="child::*[1][name()='mmlmi'][#mathcolor]">delete</xsl:if>
<xsl:if test="not(child::*[name()='mmlmi'][#mathcolor])"><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:if>
</xsl:for-each>
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:when>
<xsl:otherwise><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</mmlmsubsup>
</xsl:template>
</xsl:stylesheet>
Required OutPut:
Remove the "mmlmi" element of attribute "mathcolor", if mmlmi found as first child for second and third mmlmrow of mmlmsubsub ancetor.
Remove the "mmlmi" element of attribute "mathcolor", if mmlmi found as
first child for second and third mmlmrow of mmlmsubsub ancetor.
I think that translates to:
<xsl:template match="mmlmi[#mathcolor]
[local-name(ancestor::mmlmsubsup/mmlmrow[2]/*[1])='mmlmi']
[local-name(ancestor::mmlmsubsup/mmlmrow[3]/*[1])='mmlmi']" />
It's hard to be sure because (1) the formulation is not quite clear, and (2) the source XML is not good testing material.

XSLT 1.0 select value-of in node set with string

I have some trouble with selecting values in node set. I have a string variable,
which concatenate in path of next existed node in xml. But when i try to select valu from it,
it results in paste of value of this variable, not the value of node. I can`t find how i can
convert string to node set for proper selection. Please, help.
<xsl:for-each select="result/node()">
<xsl:copy>
<xsl:for-each select="./node()">
<xsl:copy>
<xsl:attribute name="rating">
<xsl:text>0</xsl:text>
</xsl:attribute>
<xsl:choose>
<xsl:when test="translate(
substring(.,1,3),
$upCase,
$lowCase
) = 'id_'">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="cval"
select="concat(
'/survey/checkbox_value/',
local-name(),
'/.'
)" />
<xsl:value-of select="$cval" />
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
You don't need to convert anything. It could be done with plain xpath.
<xsl:variable name="local_name" select="local-name()"/>
<xsl:value-of select="/survey/checkbox_value/node()[
local-name() = $local_name
]"/>

inserting space in xslt

Hi I am using xslt to show the links on my webpart and i have added plus image next to my link.But I would like to add some space between them. I have added ,but this is not really working. Am i missing anything here? Please find my code below.
Thanks.
<xsl:choose>
<!-- do _self -->
<xsl:when test="contains(Link,'xxx')">
<a target="_self">
<xsl:attribute name="href">
<xsl:value-of select="URL"/>
</xsl:attribute>
<xsl:value-of select="Title"/>
</a>
</xsl:when>
<!-- use _blank (new browser window) -->
<xsl:otherwise>
<a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="URL"/>
</xsl:attribute>
<xsl:value-of select="Title"/>
</a>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="Description !=' ' ">
<img class="imageclass" src="/images/plus.gif"></img>
</xsl:when>
</xsl:choose>
My understanding is that you want to produce HTML that would display white space in the browser.
If this is so, don't use spaces -- the brouser only displays one single space for a continuous sequence of spaces.
Use nonbreaking space:  
So, instead of:
<xsl:text> </xsl:text>
use:
<xsl:text>   </xsl:text>
The xsl:text instruction is the right tool for your requeriment. As example, this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a">
<xsl:call-template name="identity"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
With this input:
<div>
link1
link1
link1
</div>
Output:
<div>link1 link1 link1 </div>