XSLT conditionally change text font - xslt

For the following xml,
<question>
<bp>Suppose a file a.xml has content:</bp>
<bp><![CDATA[<a> 1 <b> 2 <b> 3 <a> 4 </a> </b> </b> </a>]]></bp>
<bp>What is the value of the following XPath expression:</bp>
<bp>for $x in doc("a.xml")//a/b return $x/b/a/text()</bp>
</question>
In the XSLT file, I have to change the font of the text if the text between the xml tags contains
<![CDATA[ ]]>
I tried using the following code,
<xsl:for-each select="mcq:bp">
<xsl:if test="contains(. , '<![CDATA[ ]]>')">
<xsl:attribute name='font-family'>courier</xsl:attribute>
<xsl:value-of select="."/>
</xsl:if>
<xsl:value-of select="."/>
<br/>
</xsl:for-each>
But the xslt does not display anything in the browser.

This cannot be done with XSLT.
At the time XSLT is passed the parsed XML document, there isn't any information whether a text node contained CDATA sections or not -- this lexical detail is stripped-off (lost) as result of the parsing of the XML document.
CDATA isn't a string and it isn't part of the text node. Therefore, it is wrong to try to detect a CDATA section by using the contains() function.

Related

Get Line Item value from XML using XSLT

Need to get Line Item value from below XML using xslt.
Input Xml :
<Root>
<Table>
<Row1 ColumnA_1="1A" ColumnB_1="1B" ColumnC_1="1B"/>
<Row2 ColumnA_2="2A" ColumnB_2="2B" ColumnC_2="2C"/>
<Row3 ColumnA_3="3A" ColumnB_3="3B" ColumnC_3="3C"/>
<Row4 .......
<Rown>
</Table>
</Root>
we can get Tag value without loop using below code:
<xsl:value-of select="/Root/Table/Row1/#ColumnA_1"/>
<xsl:value-of select="/Root/Table/Row2/#ColumnA_2"/>
How we can get Line Item value using below loop ?
<xsl:for-each select="Root/Table">
<xsl:for-each select="./*">
<Row><xsl:value-of select="/Root/Table/*/#ColumnA_ + position()"/</Row>
</xsl:for-each>
</xsl:for-each>

How to prevent self closing tags as well empty tags after transforming

I have in an input file:
<a></a>
<b/>
<c>text</c>
I need to converting this to string. Using transformer I am getting below output:
<a/> <!-- Empty tags should not collapse-->
<b/>
<c>text</c>
If I use xslt and output method is "HTML", I get the below output:
<a></a> <!-- This is as expected-->
<b></b> <!-- This is not expected-->
<c>text</c>
I want the structure same as in input file. It is required in my application since I need to calculate index and it will be very difficult to change the index calution logic.
What would be the correct XSLT to use?
What XSLT processor? XSLT is merely a language to transform xml so "html output" is dependent on the processor.
I'm going to guess this first solution is too simple for you but i've had to use this to avoid processing raw html
<xsl:copy-of select="child::node()" />
as this should clone the raw input.
In my case, I have used the following to extract all nodes that had the raw attribute:
<xsl:for-each select="xmlData//node()[#raw]">
<xsl:copy-of select="child::node()" />
</xsl:for-each>
Other options:
2) Add an attribute to each empty node depending on what you want it to do later ie role="long", role="short-hand".
3)
Loop through each node (xsl:for-each)
<xsl:choose>
<xsl:when test="string-length(.)=0"> <!-- There is no child-->
<xsl:copy-of select="node()" />
</xsl:when>
<xsl:otherwise>
...whatever normal processing you have
</xsl:otherwise>
4) Redefine your problem. Both are valid XHTML/XML, so perhaps your problem can be reframed or fixed elsewhere.
Either way, you may want to add more information in your question so that we can reproduce your problem and test it locally.
P.S. Too much text/code to put in a comment, but that's where this would belong.
A possible alternative is to use disable-output-escaping like this:
<xsl:text disable-output-escaping="yes"><a></a></xsl:text>
But I understand that this is a dirty solution...

xslt matching and stripping

I have a XML structure like this, just some valid XML structure mixed with HTML tags. I am trying to match <p>MyHeader</p> in the section and set it to empty.
That is after running the XSLT on this structure, i don't want to print the <p>MyHeader</p> tag.
<abstract>
<section>
<p>MyHeader</p>
<p> other content in section </p>
<h1> other content in section </h1>
</section>
</abstract>
Here's what I am trying in the XSL
<xsl:template match="abstract/section/p">
<xsl:choose>
<xsl:when test="text() ='MyHeader'"></xsl:when>
<xsl:otherwise><xsl:apply-templates /></xsl:otherwise>
</xsl:choose>
</xsl:template>
any ideas on what's wrong with my code above? I dont see <p>MyHeader</p> tag being stripped out.
<xsl:template match="abstract/section/p">
<xsl:choose>
<xsl:when test="text() ='MyHeader'"></xsl:when>
<xsl:otherwise><xsl:apply-templates /></xsl:otherwise>
</xsl:choose>
</xsl:template>
what's wrong with my code
Nothing wrong with the code shown -- the problem is in the code you haven't shown to us.
Guessing:
The template isn't selected for execution.
There is an explicit <xsl:copy-of> selecting this p element.
Recommendation: just use:
<xsl:template match="abstract/section/p[.='MyHeader']"/>

xpath 2.0 query - how to test if the current element is the first element with this name in a xml document

I have the following xsl template:
<xsl:template match="para">
<fo:block xsl:use-attribute-sets="paragraph.para">
<!-- if first para in document -->
<!--<xsl:if test="//para[1] intersect .">-->
<xsl:if test="//para[1] intersect .">
<xsl:attribute name="space-after">10pt</xsl:attribute>
<xsl:attribute name="background-color">yellow</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="preceding-sibling::*[1][self::title]">
<xsl:attribute name="text-indent">0em</xsl:attribute>
</xsl:when>
<xsl:when test="parent::item">
<xsl:attribute name="text-indent">0em</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="text-indent">1em</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
The problem I am having is verifying that the current node of the template is the very first para node in the document from the following xml:
<document>
<section>
<paragraph>
<para>Para Text 1*#</para>
<para>Para Text 2</para>
</paragraph>
</section>
<paragraph>
<para>Para Text 3*</para>
<para>Para Text 4</para>
<para>Para Text 5</para>
<sub-paragraph>
<para>Para Text 6*</para>
<para>Para Text 7</para>
</sub-paragraph>
</paragraph>
<appendix>
<paragraph>
<para>Para Text 8*</para>
</paragraph>
<paragraph>
<para>Para Text 9</para>
</paragraph>
</appendix>
</document>
the xpath I am currently using is "//para[1] intersect ." which is selecting the first para for each group of para (denoted with a * in XML sample). Any ideas on how I can just select the first occurance of para within document (denoted with a #)?
In XPath 1.0 (XSLT 1.0) one can use:
count( (//para)[1] | .) = 1
This works also in XPath 2.0, but may not be as efficient as using the intersect operator.
I would recommend the following XPath 2.0 expression:
(//para)[1] is .
Do note the use of the XPath 2.0 is operator.
I have worked out the solution myself, a slight change is needed in the xpath adding brackets around the //para limits the selection:
"(//para)[1] intersect ." you can also use "(//para)[1] is ." to get the same result, and on this occassion I belive the "is" version is more readable.

How to access variable in CDATA from XSLT?

I am using XSLT Transformation and need to put some data in CDATA section and that value is present in a variable.
Query: How to access variable in CDATA ?
Sample Given Below:
<xsl:attribute name ="attributeName">
<![CDATA[
I need to access some variable here like
*<xsl:value-of select ="$AnyVarible"/>*
]]>
</xsl:attribute>
How can I use varibale in CDATA ?
Note: I can not use --> <![CDATA[<xsl:value-of select ="$AnyVarible"/>]]>
Thanks in advance.
I got the solution for this...FYI for everyone...
<xsl:text
disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:value-of select ="$AnyVarible"/>
<xsl:text
disable-output-escaping="yes">]]></xsl:text>
CDATA is just text like any other element contents...
But using the xsl:output element you should be able to specify which elements are to be written as CDATA with the cdata-section-elements attribute.
EDIT:
Now that there is a valid sample, I guess you mean this:
<xsl:attribute name ="attributeName">
<![CDATA[
I need to access some variable here like
*]]><xsl:value-of select ="$AnyVarible"/><![CDATA[*
]]>
</xsl:attribute>
If you want to include CDATA sections in your output, you should use the cdata-section-elements atribute of xsl:output. This is a list of element names. Any such elements will have their text content wrapped in CDATA.
<xsl:output cdata-section-elements ="foo" />
<foo>
<xsl:value-of select="$bar' />
</foo>