Some outpost result using two condition - xslt

I have to transform xml file where i should check field id '0', field id '1' and sum field id '2'. For example I have:
<document>
<line id="0">
<field id="0">MAR</field>
<field id="1">doc1</field>
<field id="2">2</field>
</line>
<line id="1">
<field id="0">MAR</field>
<field id="1">doc2</field>
<field id="2">3</field>
</line>
<line id="2">
<field id="0">AAA></field>
<field id="1">doc4</field>
</line>
<line id="3">
<field id="0">MAR</field>
<field id="1">doc1</field>
<field id="2">4</field>
</line>
</document>
result should be:
<type-MAR>
<document>doc1</document>
<sum>6</sum>
</type-MAR>
<type-MAR>
<document>doc2</document>
<sum>3</sum>
</type-MAR>
there I should take all MAR lines, and show some results which are depends of field id '1'.
My idea was, first off all do cycle(for each) and use condition(when). Maybe somebody offer more omptimal decision.
I add new note, how to check if data comes like that:
<field id="0">MAR999</field>
<field id="1">doc1-1231</field>
First field i try to use function contains 'MAR', others substring-before '-'. but I stuck when I try it use on Yours program. maybe you can take some advice for it?

This transformation:
<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:key name="kLineById0Id1" match="line[field[#id=2]]"
use="concat(field[#id=0],'+',field[#id=1])"/>
<xsl:template match=
"line[field[#id=2]
and
generate-id()
=
generate-id(key('kLineById0Id1',
concat(field[#id=0],
'+',field[#id=1])
)[1])
]
">
<xsl:element name="type-{field[#id=0]}">
<document>
<xsl:value-of select="field[#id=1]"/>
</document>
<sum>
<xsl:value-of select=
"sum(key('kLineById0Id1',
concat(field[#id=0],
'+',field[#id=1])
)
/field[#id=2]
)
"/>
</sum>
</xsl:element>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided XML document:
<document>
<line id="0">
<field id="0">MAR</field>
<field id="1">doc1</field>
<field id="2">2</field>
</line>
<line id="1">
<field id="0">MAR</field>
<field id="1">doc2</field>
<field id="2">3</field>
</line>
<line id="2">
<field id="0">AAA></field>
<field id="1">doc4</field>
</line>
<line id="3">
<field id="0">MAR</field>
<field id="1">doc1</field>
<field id="2">4</field>
</line>
</document>
produces the wanted, correct result:
<type-MAR>
<document>doc1</document>
<sum>6</sum>
</type-MAR>
<type-MAR>
<document>doc2</document>
<sum>3</sum>
</type-MAR>
Explanation: The Muenchian method for grouping is used with the key defined as the concatenation of two elements.

<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:key name="kLine" match="line" use="field[#id='1']"/>
<xsl:template match="/*">
<r>
<xsl:apply-templates select="line
[field[#id='0'] = 'MAR']
[count(
. | key('kLine', field[#id='1'])[1]
) = 1]
"/>
</r>
</xsl:template>
<xsl:template match="line">
<type-MAR>
<document>
<xsl:value-of select="field[#id='1']"/>
</document>
<sum>
<xsl:value-of select="
sum(
key('kLine', field[#id='1'])/
field[#id='2']
)"/>
</sum>
</type-MAR>
</xsl:template>
</xsl:stylesheet>
Correct against your sample will be:
<r>
<type-MAR>
<document>doc1</document>
<sum>6</sum>
</type-MAR>
<type-MAR>
<document>doc2</document>
<sum>3</sum>
</type-MAR>
</r>

This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kLineById0-Id1" match="line"
use="concat(field[#id='0'],'+',field[#id='1'])"/>
<xsl:param name="pId0" select="'MAR'"/>
<xsl:template match="document">
<result>
<xsl:apply-templates select="line[generate-id()=
generate-id(
key('kLineById0-Id1',
concat($pId0,
'+',
field[#id='1']
)
)[1]
)]"/>
</result>
</xsl:template>
<xsl:template match="line">
<xsl:element name="type-{$pId0}">
<document>
<xsl:value-of select="field[#id='1']"/>
</document>
<sum>
<xsl:value-of select="sum(key('kLineById0-Id1',
concat(field[#id='0'],
'+',
field[#id='1']
)
)/field[#id='2']
)"/>
</sum>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<result>
<type-MAR>
<document>doc1</document>
<sum>6</sum>
</type-MAR>
<type-MAR>
<document>doc2</document>
<sum>3</sum>
</type-MAR>
</result>
Note: Grouping by both #id attributes, sum group, dynamic element name, parameterized first #id.

Thanks for answers, I use Flack decision and make some correction:
<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:key name="kLine" match="line" use="substring(field[#id='1'],1,4)"/>
<xsl:template match="/*">
<document>
<xsl:apply-templates select="line[contains(field[#id='0'], 'MAR')][count(. | key('kLine', substring(field[#id='1'],1,4))[1]) = 1]"/>
</document>
</xsl:template>
<xsl:template match="line">
<type-MAR>
<document>
<xsl:value-of select="substring(field[#id='1'],1,4)"/>
</document>
<sum>
<xsl:value-of select="sum(key('kLine', substring(field[#id='1'],1,4))/field[#id='2'])"/>
</sum>
</type-MAR>
</xsl:template>
</xsl:stylesheet>
Dimitre and Alejandro decisions are also good and useful(maybe more professional). But Dimitre more concentrate on my task which I wrote, for example he use condition to check if we have the second field(I didn't wrote that not only MAR could have field2). Alejandro to check it use parameter, so for me it was a good lesson to search more information how to use it, because with xsl language I have less than one month experience. So for me was difficult to prepair Yours programs for my work. Flack text was more understandable for me as a beginner.

Related

How to split document by fields id?

Please tell me how to split document by fields id. For example doc number are saved in line [#id=0]/field[#id=1] and line[#id=0]/field[#id=2], in line[#id>0] are saved codes and values.
XML example:
<document>
<sheet id="0" name="Sheet1">
<line id="0">
<field id="0"><![CDATA[Code]]></field>
<field id="1"><![CDATA[01]]></field>
<field id="2"><![CDATA[02]]></field>
</line>
<line id="1">
<field id="0"><![CDATA[9772]]></field>
<field id="1"><![CDATA[9.0]]></field>
<field id="2"><![CDATA[5.0]]></field>
</line>
<line id="5">
<field id="0"><![CDATA[9771]]></field>
<field id="1"><![CDATA[1.0]]></field>
<field id="2"/>
</line>
<line id="1">
<field id="0"><![CDATA[9773]]></field>
<field id="1"><![CDATA[8.0]]></field>
<field id="2"><![CDATA[4.0]]></field>
</line>
</sheet>
</document>
if needed result:
<documents>
<document>
<header>
<number>01</number>
</heder>
<line>
<line-item>
<lineNumber>1</lineNumber>
<Code>9772</Code>
<value>9.0</value>
</line-item>
<line-item>
<lineNumber>2</lineNumber>
<Code>9771</Code>
<value>1.0</value>
</line-item>
<line-item>
<lineNumber>3</lineNumber>
<Code>9773</Code>
<value>8.0</value>
</line-item>
</line>
</document>
<document>
<header>
<number>02</number>
</heder>
<line>
<line-item>
<lineNumber>1</lineNumber>
<Code>9772</Code>
<value>5.0</value>
</line-item>
<line-item>
<lineNumber>2</lineNumber>
<Code>9773</Code>
<value>4.0</value>
</line-item>
</line>
</document>
</documents>
Transformation should work on xsl:stylesheet version="1.0"
Try this ...
Solution 1: Procedural
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*" />
<xsl:template match="/">
<documents>
<xsl:apply-templates select="document/sheet/line[#id='0']/field[#id!='0']" />
</documents>
</xsl:template>
<xsl:template match="field[#id!='0']">
<document>
<header>
<number><xsl:value-of select="." /></number>
</header>
<line>
<xsl:call-template name="line-item-template" >
<xsl:with-param name="value-id" select="#id" />
<xsl:with-param name="lines" select="../../line[#id!='0']"/>
</xsl:call-template>
</line>
</document>
</xsl:template>
<xsl:template name="line-item-template">
<xsl:param name="value-id" />
<xsl:param name="lines" />
<xsl:for-each select="$lines[field[#id=$value-id]!='']" >
<line-item>
<lineNumber><xsl:value-of select="format-number(position(),'00')" /></lineNumber>
<Code><xsl:value-of select="field[#id='0']" /></Code>
<value><xsl:value-of select="field[#id=$value-id]" /></value>
</line-item>
</xsl:for-each >
</xsl:template>
</xsl:stylesheet>
.. or try this ...
Solution 2: Template-o-phile
This solution hooks into the node that relates to the output node.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*" />
<xsl:template match="/">
<documents>
<xsl:apply-templates select="document/sheet/line[#id='0']/field[#id!='0']" />
</documents>
</xsl:template>
<xsl:template match="field[parent::line[#id='0']][#id!='0']">
<document>
<header>
<number><xsl:value-of select="." /></number>
</header>
<line>
<xsl:variable name="value-index" select="#id" />
<xsl:apply-templates select="../../line[#id!='0']/field[#id=$value-index]" />
</line>
</document>
</xsl:template>
<xsl:template match="field[parent::line[#id!='0']][.!='']">
<xsl:variable name="current" select="." />
<xsl:variable name="value-index" select="#id" />
<line-item>
<lineNumber><xsl:value-of select="format-number( count(
preceding::line[field[#id=$value-index]!='']
[..=$current/../..]
),'00')" /></lineNumber>
<Code><xsl:value-of select="../field[#id='0']" /></Code>
<value><xsl:value-of select="." /></value>
</line-item>
</xsl:template>
</xsl:stylesheet>
Now imagine solving this problem for XSLT 2.0. Now that would be fun! :-)

how to add condition which check xml data with lookup table

I want to ask. there is posible to add condition which will be checking xml data with lookup table, and if we didnt't have value in lookup table add const 8 to output?
xslt Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="Department" match="Department" use="../Collection"/>
<xsl:template match="/">
<document>
<xsl:apply-templates/>
</document>
</xsl:template>
<xsl:template match="line">
<xsl:variable name="inputDep" select="field[#id='3']"/>
<Department>
<xsl:for-each select="document('lookup.xml')">
<xsl:for-each select="key('Deparment',$inputDep)">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:for-each>
</Department>
</xsl:template>
</xsl:stylesheet>
lookup table:
<document>
<line-item>
<Collection>1</Collection>
<Department>3</Department>
</line-item>
<line-item>
<Collection>2</Collection>
<Department>1</Department>
</line-item>
<line-item>
<Collection>3</Collection>
<Department>2</Department>
</line-item>
</document>
xml file:
<document>
<line id="0">
<field id="3"><![CDATA[1]]></field>
</line>
<line id="1">
<field id="3"/>
</line>
<line id="2">
<field id="3"/><![CDATA[4]]></field>
</line>
</document>
result:
<Department>3<Department>
<Department>8<Department>
<Department>8<Department>
You could assign the looked-up value to a variable and choose what to output based on whether anything was found.
Edit 2: A full demonstration stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="Department" match="Department" use="../Collection"/>
<xsl:template match="/">
<document>
<xsl:apply-templates/>
</document>
</xsl:template>
<xsl:template match="line">
<xsl:variable name="inputDep" select="field[#id='3']"/>
<Department>
<xsl:for-each select="document('lookup.xml')">
<xsl:variable name="value" select="key('Department',$inputDep)"/>
<xsl:choose>
<xsl:when test="$value">
<xsl:value-of select="$value"/> <!-- see note -->
</xsl:when>
<xsl:otherwise>8</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Department>
</xsl:template>
</xsl:stylesheet>
Note: Replaced the xsl:for-each loop in the original stylesheet with a simple xsl:value-of, assuming that the looping the values was not intentional. If it actually was, you can replace this with a for-each loop.

How to sum if we use substring function

I want to ask how to get total amount if we use substring function,
for example I have this xml,
<document>
<line id="0">
<field id="0"><![CDATA[AAAddd17aaass]]></field>
</line>
<line id="1">
<field id="0"><![CDATA[DDDaaa33sssaa]]></field>
</line>
</document>
I should sum(substring(field[#id='0'], 7,2)). Then I try to do that, I get this error message: Current Item is 'NaN of type xs:string. (I try to use number function but it doesn't help)
Please advice me how to solve it.
Easy in XSLT 2.0:
sum(field[#id='0']/number(substring(., 7,2)))
Rather more difficult in XSLT 1.0: see for example http://www.velocityreviews.com/forums/t170401-sum-over-computed-value.html
In XSLT 1.0 if you don't want to write recursive templates yourself, you can use the transform-and-sum template from FXSL.
See how to use it here.
Here is the full transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:func-transform="f:func-transform"
exclude-result-prefixes="xsl f func-transform"
>
<xsl:import href="transform-and-sum.xsl"/>
<!-- to be applied on testTransform-and-sum.xml -->
<xsl:output method="text"/>
<func-transform:func-transform/>
<xsl:template match="/">
<xsl:call-template name="transform-and-sum">
<xsl:with-param name="pFuncTransform"
select="document('')/*/func-transform:*[1]"/>
<xsl:with-param name="pList" select="/*/*/*"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="func-transform:*" mode="f:FXSL">
<xsl:param name="arg1" select="0"/>
<xsl:value-of select="number(substring($arg1, 7,2))"/>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<document>
<line id="0">
<field id="0"><![CDATA[AAAddd17aaass]]></field>
</line>
<line id="1">
<field id="0"><![CDATA[DDDaaa33sssaa]]></field>
</line>
</document>
the wanted, correct result is produced:
50

xpath get matches in sublist

I've got the following xml:
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="descriptione" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
I'm using XSLT to transform it, and I'm need, for each update, to get the fields in the vo that correspond to the field defined in the input. It would be something like this:
<xsl:variable name="fields" select="vo/field" />
<xsl:for-each select="update">
<xsl:variable name='fieldsForInput' select = "$fields[#name]=input/fields[#name]"/>
<xsl:for-each select="$fieldsForInput">
<xsl:value-of select="#type"/> <xsl:value-of select="#name"/>
<xsl:for-each>
</xsl:for-each>
But it doesn't found anything. Any ideas?
Thanks
JL
From the shown fragments it's difficult helping you and understadning what you want. However your case seems perfect for using xsl:key.
For example, if you create a key at the beginning of the transform like this:
<xsl:key name="fields" match="vo/field" use="#name"/>
You can use it inside your matching template as follows:
<xsl:for-each select="update/input">
<xsl:copy-of select="key('fields',current()/field/#name)"/>
</xsl:for-each>
I would not use a xsl:foreach anyway. But it's hard to give you a complete solution if you provide only fragments. Also is not clear if you want just match or replace field.
Example showing how to get the field name/type for each update/input/field.
XSLT 1.0 tested with Saxon 6.5.5
<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:key name="fields" match="vo/field" use="#name"/>
<xsl:template match="/root">
<xsl:apply-templates select="update"/>
</xsl:template>
<xsl:template match="update">
<xsl:value-of select="concat('-',#method,'
')"/>
<xsl:apply-templates select="input/field"/>
</xsl:template>
<xsl:template match="input/field">
<xsl:value-of select="concat('--',#name,' ',key('fields',#name)/#type,'
')"/>
</xsl:template>
</xsl:stylesheet>
Applied on:
<root>
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="description" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
<update method="deleteMember" modificationMode="DELETE_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
</root>
Produces:
-addMember
--member String[]
--description String
-deleteMember
--member String[]
--description String
Two solutions:
Solution1 (no keys):
<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=
"vo/field[#name=../../update/*/*/#name]">
<xsl:value-of select="concat(#name,' ',#type,'
')"/>
</xsl:template>
</xsl:stylesheet>
When applied on the provided XML document (corrected to be made well-formed):
<t>
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="description" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
</t>
the wanted, correct result is produced:
description String
member String[]
Solution2 (using a key):
<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:key name="kFieldByName" match="vo/field"
use="#name"/>
<xsl:template match="/*">
<xsl:apply-templates mode="selected" select=
"key('kFieldByName', update/*/*/#name)"/>
</xsl:template>
<xsl:template match="vo/field" mode="selected">
<xsl:value-of select="concat(#name,' ',#type,'
')"/>
</xsl:template>
</xsl:stylesheet>
when applied on the same XML document (above), the same correct result is produced:
description String
member String[]

How to find start(min) and end(max) date in xml file?

I have an XML file. I should find for same field2 start(min) date and End(max) date from field3. Maybe xsl have some function to find it.Because I try do it trying to find min month and min day and max month, max day.
XML:
<document>
<line id="0">
<field id="2">X111</field>
<field id="3">2011-03-31</field>
</line>
<line id="1">
<field id="2">X111</field>
<field id="3">2011-04-04</field>
</line>
<line id="2">
<field id="2">X111</field>
<field id="3">2011-04-02</field>
</line>
<line id="3">
<field id="2">X222</field>
<field id="3">2011-04-04</field>
</line>
<line id="4">
<field id="2">X222</field>
<field id="3">2011-04-01</field>
</line>
<line id="4">
<field id="2">X333</field>
<field id="3">2011-04-01</field>
</line>
</document>
Output:
<document>
<Message>
<ID>X111</ID>
<dateStart>2011-03-31</dateStart>
<dateEnd>2011-04-04</dateEnd>
</Message>
<Message>
<ID>X222</ID>
<dateStart>2011-04-01</dateStart>
<dateEnd>2011-04-04</dateEnd>
</Message>
<Message>
<ID>X333</ID>
<dateStart>2011-04-01</dateStart>
<dateEnd>2011-04-01</dateEnd>
</Message>
</document>
Please help to solve it. I'm working with stylesheet version="1.0".
This can probably be optimized but it returns the requested results:
<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:key name="test" match="line" use="field[#id=2]"/>
<xsl:template match="/">
<document>
<xsl:for-each select="//line[generate-id()=generate-id(key('test',field[#id=2]))]">
<xsl:sort select="field[#id=2]"/>
<Message>
<ID>
<xsl:value-of select="field[#id=2]"/>
</ID>
<xsl:apply-templates select="key('test',field[#id=2])">
<xsl:sort select="field[#id=3]"/>
</xsl:apply-templates>
</Message>
</xsl:for-each>
</document>
</xsl:template>
<xsl:template match="line">
<xsl:if test="position()=1">
<dateStart>
<xsl:value-of select="field[#id=3]"/>
</dateStart>
</xsl:if>
<xsl:if test="position()=last()">
<dateEnd>
<xsl:value-of select="field[#id=3]"/>
</dateEnd>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I upvoted #mousio's answer, but I'd prefer to see the first of each line type handled in its own template. So, in the spirit of TMTOWTDI, here's how I would have done it:
<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:key name="byField2" match="line" use="field[#id=2]" />
<xsl:template match="/">
<document>
<xsl:apply-templates select="document/line" />
</document>
</xsl:template>
<xsl:template match="line[count(.|key('byField2', field[#id=2])[1])=1]">
<Message>
<ID><xsl:value-of select="field[#id=2]" /></ID>
<xsl:apply-templates select="key('byField2', field[#id=2])" mode="m">
<xsl:sort select="field[#id=3]" />
</xsl:apply-templates>
</Message>
</xsl:template>
<xsl:template match="line" mode="m">
<xsl:if test="position()=1">
<dateStart><xsl:value-of select="field[#id=3]" /></dateStart>
</xsl:if>
<xsl:if test="position()=last()">
<dateEnd><xsl:value-of select="field[#id=3]" /></dateEnd>
</xsl:if>
</xsl:template>
<xsl:template match="line" />
</xsl:stylesheet>
I think this is easier to read (and probably more efficient on large documents, since it doesn't abuse //).
This transformation shows how to find the wanted minimum and maximum:
<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="line">
<xsl:sort select="field[#id=3]"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="line">
<xsl:if test="position()=1">
Earliest:
<xsl:copy-of select="."/>
</xsl:if>
<xsl:if test="position()=last()">
Latest:
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<document>
<line id="0">
<field id="2">X111</field>
<field id="3">2011-03-31</field>
</line>
<line id="1">
<field id="2">X111</field>
<field id="3">2011-04-04</field>
</line>
<line id="2">
<field id="2">X111</field>
<field id="3">2011-04-02</field>
</line>
<line id="3">
<field id="2">X222</field>
<field id="3">2011-04-04</field>
</line>
<line id="4">
<field id="2">X222</field>
<field id="3">2011-04-01</field>
</line>
<line id="4">
<field id="2">X333</field>
<field id="3">2011-04-01</field>
</line>
</document>
produces:
Earliest:
<line id="0">
<field id="2">X111</field>
<field id="3">2011-03-31</field>
</line>
Latest:
<line id="3">
<field id="2">X222</field>
<field id="3">2011-04-04</field>
</line>
Explanation:
Choosing the first and last element from the sorted node-list. The dates are in a "good" format, so they are sorted just as strings.