How to pass variable name inside for-each loop in xslt - xslt

I'm new to Xslt I'm reading xml data using xslt. for example
<head>
<root>
<data>
<Name>xxx</Name>
<age>10</age>
</data>
<data>
<Name>yyy</Name>
<age>20</age>
</data>
<data>
<Name>zzz</Name>
<age>15</age>
</data>
</root>
</head>
When I tried use below xslt
<xsl:template match="head">
<xsl:element name="Root1">
<xsl:for-each select="//head/root/data">
<xsl:element name="name">
<xsl:value-of select="$select_Name"/>
</xsl:element>
<xsl:element name="age">
<xsl:value-of select="$select_age"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
My c# code is
XslTransform xsl=new XslTransform();
xsl.Load("xsltfile");
xsl.Transform("inputxml.xml","outputxml.xml");
I'm not getting proper output when i use the above xslt file. whereas when I give the xpath of the element to a variable in another xslt file and include the xslt into this xslt and pass variable name instead of hardcoded value <xsl:value-of select="$select_Name"/> like this whereas $name is declared as <xsl:variable name="select_Name" select="//head/root/data/Name"/> im getting the value of name for the field of Age. Anyone faced this kind of issue? or can you share how to pass the variable name instead of element name for the value inside for-each loop?

Related

Need the URL coming in both attribute and content

My input is having URL, this needs to come in both attribute value and content value in the output using XSL:
My Input xml is:
<link>
<Url>http://tneb.gov/</Url>
</link>
XSL I Used as:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Url">
<xsl:element name="xref">
<xsl:attribute name="format">
<xsl:text>html</xsl:text>
</xsl:attribute>
<xsl:attribute name="href">
<xsl:value-of select="ancestor-or-self::link/Url"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output I get as:
<xref format="html" href="http://tneb.gov/"/>
But i need as:
<xref format="html" href="http://tneb.gov/">http://tneb.gov/</xref>
Please give me suggestion on this. Thanks in advance
Why don't you do simply:
<xsl:template match="Url">
<xref format="html" href="{.}">
<xsl:value-of select="."/>
</xref>
</xsl:template>
Notes:
It's not necessary to use xsl:element if the name of the element is
known - see: https://www.w3.org/TR/xslt20/#literal-result-element
Learn about attribute value templates:
https://www.w3.org/TR/xslt20/#attribute-value-templates
Learn about the context item expression:
https://www.w3.org/TR/xpath20/#id-context-item-expression

how to call my template and my function sequentially in xslt 2.0?

I am using xslt2.0 for convert one xml format to another xml format. This is my sample xml document.
<w:document>
<w:body>
<w:p>Para1</w:p>
<w:p>Para2</w:p>
<w:p>Para3</w:p>
<w:p>Para4</w:p>
</w:body>
</w:document>
Initially this is my xml format.so, i handled each and every <w:p> elements through my function in xslt given below...
<xsl:template match="document">
<Document>
<xsl:sequence select="mf:group(body/p, 1,count(//w:body//w:p)-1)"/>
</Document>
</xsl:template>
So,In that xslt function, i have coded how to reformat those elements.It's working fine...
But now,Xml format is restructured like given below...
<w:document>
<w:body>
<w:tbl><!--some text with children elements--></w:tbl>
<w:tbl><!--some text with children elements--></w:tbl>
<w:p>Para1</w:p>
<w:p>Para2</w:p>
<w:p>Para3</w:p>
<w:p>Para4</w:p>
</w:body>
</w:document>
So, As of now i have to handle both and elements in a same sequence.....
What i want to do is,
If i encounter elemtents then i have to call my template given below...
<xsl:template match="document">
<Document>
<xsl:for-each select="w:tbl">
<xsl:apply-templates select="w:tbl">
</xsl:apply-templates>
</xsl:for-each>
<xsl:sequence select="mf:group(body/p, 1,count(//w:body//w:p)-1)"/>
</Document>
</xsl:template>
<xsl:template match="w:tbl">
<!--xslt code here -->
</xsl:template>
But the for-each statement is not executed when I trying transformation...
So, Please guide me to get out of this issue...
I think instead of
<xsl:template match="document">
<Document>
<xsl:for-each select="w:tbl">
<xsl:apply-templates select="w:tbl">
</xsl:apply-templates>
</xsl:for-each>
<xsl:sequence select="mf:group(body/p, 1,count(//w:body//w:p)-1)"/>
</Document>
</xsl:template>
you simply want
<xsl:template match="document">
<Document>
<xsl:apply-templates select="w:body/w:tbl"/>
<xsl:sequence select="mf:group(body/p, 1,count(//w:body//w:p)-1)"/>
</Document>
</xsl:template>
If that does not do what you want then please show the result you want.

Transform tag only if other kind of tag will follow

I'd like to amend an existing xsl file so that the tag <Empty> in the source document is only transformed if there will follow another sibling which is not this tag. A kind of truncate of these tags to the end.
Currently I have:
...
<xsl:template match="Expression">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="Empty">
<xsl:value-of select="."/>
</xsl:template>
Can this be achieved with xslt?
Sample input
<root>
<dummy1>Test1</dummy1>
<Empty>Empty1</Empty>
<Empty>Empty2</Empty>
<dummy2>Test2</dummy2>
<Empty>Empty3</Empty>
<Empty>Empty4</Empty>
<Empty>Empty5</Empty>
</root>
desired output:
Test1Empty1Empty2Test2
Please post a small input sample and the corresponding result you want to create with XSLT. There is a sibling axis in XPath so doing e.g.
<xsl:template match="Empty[following-sibling::*[1][not(self::Empty)]]">
<!-- now transform here as needed -->
</xsl:template>
matches any Empty elements followed by another element that is not an Empty element but I am not sure that is all you need and what you want to do inside of the template.
Assumed Input XML as:
<?xml version="1.0" encoding="utf-8"?>
<root>
<dummy1>test</dummy1>
<Empty>do-not-copy</Empty>
<Empty>copy-this1</Empty>
<dummy2>test</dummy2>
<Empty>do-not-copy-this2</Empty>
</root>
In the above XML .. 2nd element <Empty>do-not-copy</Empty> has immediate next sibling as <Empty>copy-this1</Empty> so it should not be selected. where as 3rd element is followed-by <dummy2/> so it should be copied ..
and 5th element is <Empty>copy-this2</Empty> it's not followed by any tag .. so it should be dropped as well :)
this is the XSL code for that:
<xsl:template match="Empty[following-sibling::*[1][name()!='Empty']]">
<xsl:value-of select="."/>
</xsl:template>
I am adding up a new answer ..
If this is your XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<dummy>test</dummy>
<Empty>copy-this</Empty>
<Empty>copy-this1</Empty>
<dummy>test</dummy>
<Empty>copy-this</Empty>
<Empty>copy-this1</Empty>
<dummy>test</dummy>
<Empty>donot-copy-this2</Empty>
<Empty>donot-copy-this2</Empty>
</root>
XSLT: sample code..
<xsl:template match="dummy">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="Empty[following-sibling::*[name()!='Empty']]">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="text()"/>
Output:
testcopy-thiscopy-this1testcopy-thiscopy-this1test
I modified the proposed solutions to the following:
<xsl:template match="Empty[following-sibling::*[not(self::Empty)]]">
<xsl:value-of select="."/>
</xsl:template>
which seems to work.

insert PCDATA from the child element into an attribute

I want to insert PCDATA from the child element into a selected node attribute
XML
<root>
<tag>
<tag1>SOME TEXT</tag1>
</tag>
</root>
MY XSL
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xi="http://www.w3.org/2001/XInclude" version="1.0">
<xsl:template match="root">
<tag-out>
<xsl:attribute name="text">
<!-- What should I select? -->
<xsl:value-of select="tag/tag1/???"/>
</xsl:attribute>
<tag-out>
</xsl:template>
...........
</xsl:stylesheet>
Desired output XML
<root-out text="SOME TEXT">
<tag-out/>
</root-out>
Thanks
What's wrong with simply doing
<tag-out text="{tag/tag1}"></tag-out>
? Of course your sample with
<tag-out>
<xsl:attribute name="text">
<xsl:value-of select="tag/tag1"/>
</xsl:attribute>
<tag-out>
is also possible. But as your post is tagged XSLT 2.0 I would at least do
<tag-out>
<xsl:attribute name="text" select="tag/tag1"/>
<tag-out>
if you really need xsl:attribute.

XSL for-each and value-of

Given the xml:
<element>text</element>
...
<element>text</element>
And xsl:
<xsl:for-each select="element">
...
</xsl:for-each>
What do I need to put inside the for-each loop to access the text? There doesn't seem to be a corresponding xsl:value-of because select="", select="/", and select="element" are all wrong.
<xsl:value-of select="."/>