I have written XSLT file with the following code:
<xsl:attribute name="subCode">
<xsl:value-of select="Field[#key='XY']"/>
</xsl:attribute>
Let's say that my INPUT XML looks like this:
[...]
<Field key="XY"/>
[...]
In this case my XSLT would generate the following output:
<SomeElement subCode="">
[...]
</SomeElement>
My question is: How to ged rid of empty attribute subCode=""?
I know that it is possible by using some conditional instruction like <xsl:if>, however, this seems to be an ugly solution (because I have thousands of similar attributes generated in my XSLT).
It must be done in the same XSLT. I cannot add post-processing in additional XSLT file.
Besides that, the output XML has got its XSD Schema defined. And the schema says that this attribute is optional. Maybe there is some way to apply that XSD schema for the output XML?
Thanks in advance for any help!
Use:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<someElement>
<xsl:apply-templates mode="attr"/>
</someElement>
</xsl:template>
<xsl:template match="Field[#key='XY' and not(.='')]" mode="attr">
<xsl:attribute name="subCode">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<t>
<Field key="XY"/>
</t>
the wanted, correct result (no attribute at all is generated) is produced:
when the source XML document is this:
<t>
<Field key="XY">1</Field>
</t>
the same transformation again produces the correct, wanted result;
<someElement subCode="1"/>
You can define a template to match the attribute which will give you the correct output for a missing #key but if you also add the predicate [.!=''] it should then also ignore the attributes with no value.
<xsl:template match="#key[.!='']">
<xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
Or in your example if you only want the #key='XY' matches use:
<xsl:template match="#key[.='XY']">
<xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
Edit: Here is a more complete example that I used to test this.
Source XML
<Fields>
<Field key="XY">A</Field>
<Field key="XY">B</Field>
<Field key="">C</Field>
<Field>D</Field>
</Fields>
Accompanying XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<output>
<xsl:apply-templates />
</output>
</xsl:template>
<xsl:template match="Field">
<xsl:element name="NewField">
<xsl:apply-templates select="#*"/>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="#key[.='XY']">
<xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Result
<output>
<NewField subCode="XY">A</NewField>
<NewField subCode="XY">B</NewField>
<NewField>C</NewField>
<NewField>D</NewField>
</output>
You should apply the following templates to your attributes:
This template matches all key the attributes who's value is 'XY':
<xsl:template match="#key['XY']">
<xsl:attribute name="subCode">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
This template matches all the key attributes with a (text)value longer than 0:
<xsl:template match="#key[string-length(.)]">
<xsl:attribute name="other">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
And finally this template matches all the attributes (*) that are empty:
<xsl:template match="#*[not(string-length(.))]" />
So if you have an input like
<?xml version="1.0"?>
<Root>
<Field key='v'>One</Field>
<Field key='XY'>Two</Field>
<Field key='a'>Three</Field>
<Field key='v'>Four</Field>
<Field key='XY'>Five</Field>
<Field>Six</Field>
<Field>Seven</Field>
<Field key='b'>Eight</Field>
<Field key=''>Nine</Field>
<Field></Field>
<Field key='x'>Eleven</Field>
<Field key=''>Twelve</Field>
<Field lat='x'>Thirteen</Field>
</Root>
You can generate an output:
<?xml version='1.0' ?>
<Root>
<SomeField other="v">One</SomeField>
<SomeField subCode="XY">Two</SomeField>
<SomeField other="a">Three</SomeField>
<SomeField other="v">Four</SomeField>
<SomeField subCode="XY">Five</SomeField>
<SomeField>Six</SomeField>
<SomeField>Seven</SomeField>
<SomeField other="b">Eight</SomeField>
<SomeField>Nine</SomeField>
<SomeField/>
<SomeField other="x">Eleven</SomeField>
<SomeField>Twelve</SomeField>
<SomeField>xThirteen</SomeField>
</Root>
using the following xslt:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<Root>
<xsl:apply-templates/>
</Root>
</xsl:template>
<xsl:template match="Field">
<xsl:element name="SomeField">
<xsl:apply-templates select="#*"/>
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#key['XY']">
<xsl:attribute name="subCode">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="#key[string-length(.)]">
<xsl:attribute name="other">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="#key[not(string-length(.))]" />
</xsl:stylesheet>
Related
I am trying to append a new XML node under existing XML node but i wasn't able to achieve the desired result.
Please find my below XML,
<Root>
<Row>
<A1>0</A1>
<A2>1</A2>
<Preferred_First_Name>aaaa</Preferred_First_Name>
<Preferred_Last_Name>yyyy</Preferred_Last_Name>
<location>xxxx</location>
<ID>12345</ID>
</Row>
</Root>
I want to modify the above XML in such a way that Preferred_First_Name, Preferred_Last_Name and location node need to be under a new XML tag "Data".
The desired output should be like below,
<Root>
<Row>
<A1>0</A1>
<A2>1</A2>
<Data>
<Preferred_First_Name>aaaa</Preferred_First_Name>
<Preferred_Last_Name>yyyy</Preferred_Last_Name>
<location Descriptor="xxxx">
<ID type="ID">xxxx</ID>
<ID type="LocationID">xxxx</ID>
</location>
</Data>
<ID>12345</ID>
</Row>
</Root>
Can someone please help?
you can use below
<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet xmlns:xalan="http://xml.apache.org/xalan" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="Root">
<xsl:element name="Root">
<xsl:call-template name="Row" />
</xsl:element>
</xsl:template>
<xsl:template name="Row">
<xsl:element name="Row">
<xsl:copy-of select="Row/A1"/>
<xsl:copy-of select="Row/A2"/>
<xsl:element name="Data">
<xsl:copy-of select="Row/Preferred_First_Name"/>
<xsl:copy-of select="Row/Preferred_Last_Name"/>
<xsl:element name="location">
<xsl:attribute name="Descriptor">
<xsl:value-of select="Row/location"/>
</xsl:attribute>
<xsl:element name="ID">
<xsl:attribute name="type">
<xsl:value-of select="'ID'"/>
</xsl:attribute>
<xsl:value-of select="Row/location"/>
</xsl:element>
<xsl:element name="ID">
<xsl:attribute name="type">
<xsl:value-of select="'LocationID'"/>
</xsl:attribute>
<xsl:value-of select="Row/location"/>
</xsl:element>
</xsl:element>
<xsl:copy-of select="Row/ID"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Please let me know this helps you
If it is okay to put <ID> after <Data> mentioned by Tim C, then the optimized solution can be:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row">
<Row>
<xsl:apply-templates select="child::node()[not(self::Preferred_First_Name or self::Preferred_Last_Name
or self::location)]" />
<Data>
<xsl:apply-templates select="child::node()[self::Preferred_First_Name or self::Preferred_Last_Name
or self::location]"/>
</Data>
</Row>
</xsl:template>
</xsl:stylesheet>
I am pretty much new to xsl.Currently facing a challenge in transforming the below sample xml to required output.
Sample XML:
<root>
<types>
<entity-type>
<field-type identifier="FieldType1" proxy-ref="TypeA">
<object-name>aclProxy</object-name>
<persistence-class-name>java.lang.Long</persistence-class-name>
</field-type>
<field-type identifier="FieldType2" proxy-ref="TypeB">
<object-name>aclName</object-name>
<persistence-class-name>java.lang.String</persistence-class-name>
</field-type>
</entity-type>
</types>
<custom>
<category identifier="parent" order="1">
<name>%category.parent</name>
</category>
<category identifier="texts" order="2">
<name>%category.Texts</name>
</category>
<field identifier="ArticleID" category-ref="parent" field-type-ref="FieldType1" proxy-entity-ref="ABC">
<name>%field.name</name>
<description>%field.Article.description</description>
</field>
<field identifier="ArticleName" category-ref="texts" field-type-ref="FieldType2" proxy-entity-ref="ABCD">
<name>%field.name.text</name>
<description>%field.Articletext.description</description>
</field>
</custom>
</root>
Output
<field identifier="ArticleID">
<name>%field.name</name>
<description>%field.Article.description</description>
<category-ref-name>%category.parent</category-ref-name>
<field-type-ref>Long</field-type-ref>
<proxy-entity-ref>TypeA</proxy-entity-ref>
</field>
<field identifier="ArticleName" >
<name>%field.name.text</name>
<description>%field.Articletext.description</description>
<category-ref-name>%category.Texts</category-ref-name>
<field-type-ref>String</field-type-ref>
<proxy-entity-ref>TypeB</proxy-entity-ref>
</field>
XSLT which I have been trying:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="category" match="category" use="#identifier" />
<xsl:key name="field" match="field" use="#category-ref" />
<xsl:apply-templates select="custom[not(key('field',category/#identifier))]"/>
<xsl:template match="/">
<xsl:text>something</xsl:text>
<xsl:value-of select="category/#identifier"/>
<xsl:apply-templates select="."/>
</xsl:template>
<xsl:template match="/">
<xsl:value-of select="field/#identifier"/>
<xsl:variable name="categoryparam" select="key('category', field/#category-ref)" />
<xsl:if test="$categoryparam">
<xsl:apply-templates select="$categoryparam"/>
<xsl:text>something</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Basically the output should have only field(s) in it referring to the attributes and get the node values.
Any help is much appreciated.
Thanks in advance.
Let us start off with these 2 keys:
<xsl:key name="kCategory" match="category" use="#identifier" />
<xsl:key name="kFieldID" match="field-type" use="#identifier" />
you will need the values in category and field-type nodes later.
This template:
<xsl:template match="/">
<xsl:apply-templates select="root/custom/field"/>
</xsl:template>
will output the target field nodes
Having a template match with the field node to further manipuate the output:
<xsl:template match="field">
<xsl:copy>
<!-- copies the identifier attribute and all children -->
<xsl:copy-of select="#identifier|node()"/>
<category-ref-name>
<!-- gets the child name of the target category node
that matches the category-ref attribute -->
<xsl:value-of select="key('kCategory', #category-ref)/name"/>
</category-ref-name>
<field-type-ref>
<!-- gets the child persistence-class-name of the target
field-type node that matches the field-type-ref attribute,
with further substring manipulations -->
<xsl:value-of select="substring-after(key('kFieldID', #field-type-ref)/persistence-class-name, 'java.lang.')"/>
</field-type-ref>
<proxy-entity-ref>
<!-- gets the attribute proxy-ref of the target
field-type node that matches the field-type-ref
attribute -->
<xsl:value-of select="key('kFieldID', #field-type-ref)/#proxy-ref"/>
</proxy-entity-ref>
</xsl:copy>
</xsl:template>
The whole stylesheet is below:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kCategory" match="category" use="#identifier" />
<xsl:key name="kFieldID" match="field-type" use="#identifier" />
<xsl:template match="/">
<xsl:apply-templates select="root/custom/field"/>
</xsl:template>
<xsl:template match="field">
<xsl:copy>
<xsl:copy-of select="#identifier|node()"/>
<category-ref-name>
<xsl:value-of select="key('kCategory', #category-ref)/name"/>
</category-ref-name>
<field-type-ref>
<xsl:value-of select="substring-after(key('kFieldID', #field-type-ref)/persistence-class-name, 'java.lang.')"/>
</field-type-ref>
<proxy-entity-ref>
<xsl:value-of select="key('kFieldID', #field-type-ref)/#proxy-ref"/>
</proxy-entity-ref>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
See it in action (http://xsltfiddle.liberty-development.net/gWmuiJc).
I am new to xslt programming and xlm. I have created the code below this works fine, except that instead variable names for each column, it just shows "colno" How do I get the column names into the output?
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
exclude-result-prefixes="fmp"
>
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:variable name="kMetaData" select="fmp:METADATA/fmp:FIELD"/>
<xsl:variable name="colno"
select="count($kMetaData[following-sibling::fmp:FIELD/#NAME]) + 1" />
<xsl:template match="/fmp:FMPXMLRESULT">
<PERSON>
<xsl:apply-templates select="fmp:RESULTSET/fmp:ROW" />
</PERSON>
</xsl:template>
<xsl:template match="fmp:ROW">
<ELEMENTS>
<xsl:apply-templates select="fmp:COL" />
</ELEMENTS>
</xsl:template>
<xsl:template match="fmp:COL">
<xsl:element name="colno">
<xsl:value-of select="fmp:DATA" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
It is hard to make some suggestion without input xml. But at first sight this <xsl:element name="colno"> says "output an element <colno>". I think you should use something like <xsl:element name="{xpath/to/columnName}">
edit:
According to your input xml your template for "COL" element should look like
<xsl:template match="COL">
<xsl:variable name="colPosition" select="position()" />
<!-- Prevent spaces in NAME attribute of FIELD element -->
<xsl:variable name="colName" select="translate($kMetaData[$colPosition]/#NAME, ' ', '_')" />
<xsl:element name="{$colName}">
<xsl:value-of select="DATA"/>
</xsl:element>
</xsl:template>
Then the output looks like
<?xml version="1.0" encoding="utf-8"?>
<PERSON>
<ELEMENTS>
<FIRSTNAME>Richard</FIRSTNAME>
<LASTNAME>Katz</LASTNAME>
<MIDDLENAME>David</MIDDLENAME>
<REQUESTDT>1/1/2001</REQUESTDT>
<salutation>Mr</salutation>
<Bargaining_Unit>CSEA (02,03,04)</Bargaining_Unit>
<Field_134>b</Field_134>
</ELEMENTS>
</PERSON>
I have the following xml
<TopLevel>
<data m="R263">
<s ut="263firstrecord" lt="2013-02-16T09:21:40.393" />
<s ut="263secondrecord" lt="2013-02-16T09:21:40.393" />
</data>
<data m="R262">
<s ut="262firstrecord" lt="2013-02-16T09:21:40.393" />
<s ut="262secondrecord" lt="2013-02-16T09:21:40.393" />
</data>
</TopLevel>
I have some XSLT that does the call template but it's not itterating correctly.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="data">
<xsl:value-of select="#m" />
<xsl:variable name="vYourName" select="#m"/>
<xsl:choose>
<xsl:when test="#m='R262'">
<xsl:call-template name="R262"/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="#m='R263'">
<xsl:call-template name="R263"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="R262">
<xsl:for-each select="/TopLevel/data/s">
Column1=<xsl:value-of select="#ut" />
Column2=<xsl:value-of select="#lt" />
</xsl:for-each>
</xsl:template>
<xsl:template name="R263">
<xsl:for-each select="/TopLevel/data/s">
Column1=<xsl:value-of select="#ut" />
Column2=<xsl:value-of select="#lt" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This gives me 8 records insead of the 4 (<s> level) records. I know it has to do with my iteration ... but I am not sure how to address this.
I am also aware of the apply stylesheets but I couldn't unravel that mystery either ... If someone can help me with XSLT that will only process everything from <TopLevel> to <\TopLevel> checking the value of m at the <data> level and applying the stylesheet at the <s> level for each <s> record I will be greateful beyond belief.
I don't know what output you want to produce, but I suspect you want to replace
<xsl:for-each select="/TopLevel/data/s">
by
<xsl:for-each select="s">
that is, you only want to process the "s" elements within the "data" you are currently processing, rather than selecting all the "s" elements in the whole document.
Why not do this using apply-templates?
<xsl:template match="data">
...
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="s[../#m='R262']">
...
</xsl:template>
<xsl:template match="s[../#m='R263']">
...
</xsl:template>
If you want to use match template and apply-templates you could do the following which gives you also a text output just like your stylesheet does. So this XSLT applied to your original source XML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="data">
<xsl:value-of select="#m"/>
<xsl:apply-templates select="s"/>
</xsl:template>
<xsl:template match="s">
Column1=<xsl:value-of select="#ut"/>
Column2=<xsl:value-of select="#lt"/>
</xsl:template>
</xsl:stylesheet>
gives you this output:
<?xml version="1.0" encoding="UTF-8"?>
R263
Column1=263firstrecord
Column2=2013-02-16T09:21:40.393
Column1=263secondrecord
Column2=2013-02-16T09:21:40.393
R262
Column1=262firstrecord
Column2=2013-02-16T09:21:40.393
Column1=262secondrecord
Column2=2013-02-16T09:21:40.393
You basically only match on the s and give out the attributes "ut" and "lt". You can also output XML which would look better.
Using this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="data">
<list>
<xsl:apply-templates select="s"/>
</list>
</xsl:template>
<xsl:template match="s">
<xsl:element name="record">
<xsl:attribute name="m">
<xsl:value-of select="parent::data/#m"/>
</xsl:attribute>
<item>Column1=<xsl:value-of select="#ut"/></item>
<item>Column2=<xsl:value-of select="#lt"/></item>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
will give you this nice XML output:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<list>
<record m="R263">
<item>Column1=263firstrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
<record m="R263">
<item>Column1=263secondrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
</list>
<list>
<record m="R262">
<item>Column1=262firstrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
<record m="R262">
<item>Column1=262secondrecord</item>
<item>Column2=2013-02-16T09:21:40.393</item>
</record>
</list>
You have to adapt the original XSLT a little bit to get a nice XML structure. Also when matching s you "climb" up to element data to get the R-numbers for your attribute values.
The template matching root you need for a proper XML root element. <list> you could also get rid off then you have <record> as child of <root>.
I have several records from the DB for a corresponding record in a file.
Example
Record no. XML
<XML_FILE_HEADER file_name="sample.txt" />
<XML_RECORD record_number="1" name="John Doe" Age="21"/>
<XML_RECORD record_number="2" name""Jessica Sanchez" Age="23"/>
<XML_FILE_FOOTER total_records="2"/>
Now for each record I have an xslt template that would create the output file in xml.
For record no 1:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="xml"/>
<xsl:template match="XML_FILE_HEADER">
<xsl:element name="File">
<xsl:attribute name="FileName"><xsl:value-of select="#file_name"/></xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
For records 2 and 3:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="XML_RECORD">
<xsl:element name="Record">
<xsl:attribute name="Name"><xsl:value-of select="#name"/></xsl:attribute>
<xsl:element name="Details">
<xsl:attribute name="Age"><xsl:value-of select="#Age"/></xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
For record 4:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="XML_FILE_FOOTER">
<xsl:element name="Totals">
<xsl:attribute name="Total Records"><xsl:value-of select="#total_records"/></xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The problem with is is I would have an output of this after appending each record using the templates above:
<?xml version="1.0" encoding="UTF-8"?>
<File FileName="sample.txt"></File>
<Record Name="John Doe" Age="21"></Record>
<Record Name="Jessica Sanchez" Age="22"></Record>
<Totals Total Records="2"></Totals>
How would I be able to insert the Record and Totals elements under File? so that it would have an output like this:
<?xml version="1.0" encoding="UTF-8"?>
<File FileName="sample.txt">
<Record Name="John Doe" Age="21"></Record>
<Record Name="Jessica Sanchez" Age="22"></Record>
<Totals Total Records="2"></Totals>
</File>
Any help would be very much appreciated. Thanks.
As short and easy as this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:apply-templates select="XML_FILE_HEADER"/>
</xsl:template>
<xsl:template match="XML_FILE_HEADER">
<File FileName="{#file_name}">
<xsl:apply-templates select="../*[not(self::XML_FILE_HEADER)]"/>
</File>
</xsl:template>
<xsl:template match="XML_RECORD">
<Record name="{#name}" Age="{#Age}"/>
</xsl:template>
<xsl:template match="XML_FILE_FOOTER">
<Totals TotalRecords="{#total_records}"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML (corrected to be well-formed) document:
<t>
<XML_FILE_HEADER file_name="sample.txt" />
<XML_RECORD record_number="1" name="John Doe" Age="21"/>
<XML_RECORD record_number="2" name="Jessica Sanchez" Age="23"/>
<XML_FILE_FOOTER total_records="2"/>
</t>
the wanted, correct result is produced:
<File FileName="sample.txt">
<Record name="John Doe" Age="21"/>
<Record name="Jessica Sanchez" Age="23"/>
<Totals TotalRecords="2"/>
</File>
Explanation:
Proper use of templates.
Proper use of xsl:apply-templates for ordering the results.
Proper use of AVT (Attribute Value Templates).
Avoided the use of xsl:element
No use of xsl:call-template.
Implemented in "push style" almost completely.
What you want is the <xsl:call-template name="templatename" /> element. This allows you to call a template from inside another template.
Something like
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="xml"/>
<xsl:template match="/XML_FILE/XML_FILE_HEADER">
<xsl:element name="File">
<xsl:attribute name="FileName">
<xsl:value-of select="#file_name"/>
</xsl:attribute>
<xsl:for-each select="/XML_FILE/XML_RECORD">
<xsl:call-template name="RecordTemplate" />
</xsl:for-each>
<xsl:call-template name="TotalTemplate" />
</xsl:element>
</xsl:template>
<xsl:template name="RecordTemplate">
<xsl:element name="Record">
<xsl:attribute name="Name"><xsl:value-of select="#name"/></xsl:attribute>
<xsl:attribute name="Age"><xsl:value-of select="#Age"/></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="/XML_FILE/XML_FILE_FOOTER" name="TotalTemplate">
<xsl:element name="Totals">
<xsl:attribute name="Total Records"><xsl:value-of select="#total_records"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
of course your input you have to be XML valid (i.e. have a single root node) like so
<XML_FILE>
<XML_FILE_HEADER file_name="sample.txt" />
<XML_RECORD record_number="1" name="John Doe" Age="21"/>
<XML_RECORD record_number="2" name""Jessica Sanchez" Age="23"/>
<XML_FILE_FOOTER total_records="2"/>
</XML_FILE>