Retrieve data from a different fields, where a landmark is a symbol - xslt

i have data, which looks like:
<line id="1">
<field id="1">324</field id="1">
<field id="2">abc</field id="2">
.................................
.................................
.................................
<field id="11">324321</field id="11">
<field id="12"
><![CDATA[6256812+0000140000000990000000000009900000000004058002C]]></field>
</line id="1">
<line id="2">
<field id="1">324</field id="1">
<field id="2">abc</field id="2">
.................................
.................................
.................................
<field id="8">324321</field id="11">
<field id="9"
><![CDATA[6256813+0000040000000890000000000008900000000003648002C]]></field>
</line id="2">
<line id="3">
<field id="1">324fsf</field id="1">
<field id="2">abcdf</field id="2">
.................................
.................................
.................................
<field id="12">32432s1</field id="11">
<field id="13"
><![CDATA[6256812+0000060000000750000000000007500000000003074002C]]></field>
</line id="3">
<line id="4">
<field id="1">3fsfa24</field id="1">
<field id="2">abasc</field id="2">
.................................
.................................
.................................
<field id="18">32fasf4321</field id="11">
<field id="19"
><![CDATA[6256837+0000010000000650000000000006500000000002664003C]]></field>
</line id="5">
I need to take number before landmark '+'.
<xsl:choose>
<xsl:when test="string(field[#id='9'])">
<xsl:value-of select="number(substring(field[#id='10'], 1,7))"/>
</xsl:when>
<xsl:when test="string(field[#id='11'])">
<xsl:value-of select="number(substring(field[#id='12'], 1,7))"/>
</xsl:when>
<xsl:when test="string(field[#id='17'])">
<xsl:value-of select="number(substring(field[#id='17'], 1,7))"/>
</xsl:when>
</xsl:choose>
maybe there is more right decision?

The proper XSLT way of doing this (push style processing):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="field[contains('|9|13|19|', concat('|',#id, '|'))]">
<xsl:value-of select="substring-before(.,'+')"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document (corrected from being severely malformed):
<t>
<line id="1">
<field id="12"><![CDATA[6256812+0000140000000990000000000009900000000004058002C]]></field>
</line>
<line id="2">
<field id="9"><![CDATA[6256813+0000040000000890000000000008900000000003648002C]]></field>
</line>
<line id="3">
<field id="13"><![CDATA[6256812+0000060000000750000000000007500000000003074002C]]></field>
</line>
<line id="4">
<field id="19"><![CDATA[6256837+0000010000000650000000000006500000000002664003C]]></field>
</line>
</t>
the wanted, correct result is produced:
6256813
6256812
6256837
Do note: There is not even a single conditional xslt instruction in the transformation.

Use the substring-before function. You can use it to get the text before the first +
I'd also recommend using a separate template for each condition:
<xsl:template match="field[#id='9']">
<xsl:value-of select="substring-before(../field[#id='10'],'+')" />
</xsl:template>
Or something similar depending on the context.

Looks like a bad, brittle design to me. If you're going to rely on positional logic to parse the record, why not abandon XML and use EDI or another record-based format?
You're not using XML for what it's good for here. Tags are metadata that describe the stream. You lost it when you went to this design.
I'd recommend either using XML in a better way or going all the way to a position-based record scheme.

Related

How to access a specific node in XSL

silly question but hoping I can get some help here, I need to access specific node in XSL, the XML I am provided with looks like the below, can someone give me an idea what my XSL should look like in order to access the content of the node 'Value' I cannot no matter how i try reach that node!- any help appreciated!!!! :
<?xml version="1.0" encoding="UTF-8" ?>
<CrystalReport xmlns="urn:crystal-reports:schemas:report-detail"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:crystal-reports:schemas:report-detail http://www.businessobjects.com/products/xml/CR2008Schema.xsd">
<Group Level="1">
<Group Level="2">
<Details Level="3">
<Section SectionNumber="1">
<Field Name="Field5" FieldName="{ARTransaction.Transactions}">
<FormattedValue>0.00</FormattedValue>
<Value>0.00</Value>
</Field>
<Field Name="Field15" FieldName="{ARTransaction.PostingDate}">
<FormattedValue>8/1/2016</FormattedValue>
<Value>2016-08-01</Value>
</Field>
<Field Name="Field14" FieldName="{ARTransaction.AuditTrail}">
<FormattedValue>2016083100154</FormattedValue>
<Value>2016083100154</Value>
</Field>
<Field Name="Field13" FieldName="{ARTransaction.JobN}">
<FormattedValue>-25043</FormattedValue>
<Value>-25043</Value>
</Field>
<Field Name="Field11" FieldName="{Customer.CustomerName}">
<FormattedValue>First Church of Christ</FormattedValue>
<Value>First Church of Christ</Value>
</Field>
<Field Name="Field7" FieldName="{ARTransaction.CustomerN}">
<FormattedValue>13157</FormattedValue>
<Value>13157</Value>
</Field>
<Field Name="Field6" FieldName="{ARTransaction.InvoiceN}">
<FormattedValue>25043</FormattedValue>
<Value>25043</Value>
</Field>
<Field Name="SalesmanN1" FieldName="{ARTransaction.SalesmanN}">
<FormattedValue>22</FormattedValue>
<Value>22</Value>
</Field>
</Section>
</Details>
</Group>
</Group>
</Group>
<ReportFooter> </ReportFooter>
XSL :
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:element name="CrystalReport">
<xsl:attribute name="xsi:schemaLocation">http://www.w3.org/2001/XMLSchema-instance</xsl:attribute>
<xsl:attribute name="version">1.2</xsl:attribute>
</xsl:element>
<xsl:element name="DR">
<xsl:value-of select="Group/Group/Details/Section/Field[#Name='Field13']/Value"/>
</xsl:element>
</xsl:template>
The main problem with your attempt is that it ignores the default namespace of the source XML.
You need to declare the namespace in your stylesheet, assign it a prefix, and use that prefix when addressing the elements in the source XML. For example, the following stylesheet:
XSL 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="urn:crystal-reports:schemas:report-detail"
exclude-result-prefixes="ns1">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/ns1:CrystalReport">
<DR>
<xsl:value-of select="ns1:Group/ns1:Group/ns1:Details/ns1:Section/ns1:Field[#Name='Field13']/ns1:Value"/>
</DR>
</xsl:template>
</xsl:stylesheet>
when applied to a well-formed input such as:
XML
<CrystalReport xmlns="urn:crystal-reports:schemas:report-detail" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:crystal-reports:schemas:report-detail http://www.businessobjects.com/products/xml/CR2008Schema.xsd">
<Group Level="1">
<Group Level="2">
<Details Level="3">
<Section SectionNumber="1">
<Field Name="Field5" FieldName="{ARTransaction.Transactions}">
<FormattedValue>0.00</FormattedValue>
<Value>0.00</Value>
</Field>
<Field Name="Field15" FieldName="{ARTransaction.PostingDate}">
<FormattedValue>8/1/2016</FormattedValue>
<Value>2016-08-01</Value>
</Field>
<Field Name="Field14" FieldName="{ARTransaction.AuditTrail}">
<FormattedValue>2016083100154</FormattedValue>
<Value>2016083100154</Value>
</Field>
<Field Name="Field13" FieldName="{ARTransaction.JobN}">
<FormattedValue>-25043</FormattedValue>
<Value>-25043</Value>
</Field>
<Field Name="Field11" FieldName="{Customer.CustomerName}">
<FormattedValue>First Church of Christ</FormattedValue>
<Value>First Church of Christ</Value>
</Field>
<Field Name="Field7" FieldName="{ARTransaction.CustomerN}">
<FormattedValue>13157</FormattedValue>
<Value>13157</Value>
</Field>
<Field Name="Field6" FieldName="{ARTransaction.InvoiceN}">
<FormattedValue>25043</FormattedValue>
<Value>25043</Value>
</Field>
<Field Name="SalesmanN1" FieldName="{ARTransaction.SalesmanN}">
<FormattedValue>22</FormattedValue>
<Value>22</Value>
</Field>
</Section>
</Details>
</Group>
</Group>
</CrystalReport>
will return:
Result
<?xml version="1.0" encoding="UTF-8"?>
<DR>-25043</DR>
Note: If you're using an XSLT 2.0 processor, you can declare a xpath-default-namespace attribute and do away with the prefix.

How to group at more than one level?

I have an XML file:
<document>
<line id="0">
<field id="2">X111</field>
<field id="3">1</field>
<field id="4">222222222222</field>
</line>
<line id="1">
<field id="2">X111</field>
<field id="3">1</field>
<field id="4">111111111111</field>
</line>
<line id="2">
<field id="2">X222</field>
<field id="3">1</field>
<field id="4">111111111111</field>
</line>
<line id="3">
<field id="2">X222</field>
<field id="3">1></field>
<field id="4">111111111111</field>
</line>
<line id="4">
<field id="2">X333</field>
<field id="3">1</field>
<field id="4">111111111111</field>
</line>
</document>
From this xml file I should group field2 (after that field4 ), question will be not to how to group field 2 and get three documents but how to group field4 if they are the same?
Output:
<document>
<Result>
<Header>
<Field2>X111</Field2>
</Header>
<Line>
<Position>1</Position>
<Field4>222222222222</Field4>
<Sum>1<Sum>
<Position>2</Position>
<Field4>111111111111</Field4>
<Sum>1<Sum>
</Line>
</Result>
<Result>
<Header>
<Field2>X222</Field2>
</Header>
<Line>
<Position>1</Position>
<Field4>111111111111</Field4>
<Sum>2<Sum>
</Line>
</Result>
<Result>
<Header>
<Field2>X333</Field2>
</Header>
<Line>
<Position>1</Position>
<Field4>111111111111</Field4>
<Sum>1</Sum>
</Line>
</Result>
</document>
I'm stuck in grouping lines, I didn't know how to group the same and different fields which id= 4.
My program looks:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="kLine" match="line" use="string(field[#id=2])"/>
<xsl:key name="bLine" match="line" use="field[#id=4]"/>
<xsl:template match="document">
<document>
<xsl:apply-templates select="line[count( . | key('kLine', string(field[#id='2']))[1]) = 1]"/>
</document>
</xsl:template>
<xsl:template match="line">
<xsl:variable name="field2" select="field[#id='2']"/>
<result>
<Header>
<xsl:value-of select="field[#id='2']"/>
</Header>
<Line>
<xsl:for-each select="//line[field[#id='2']=$field2]">
<Position>
<xsl:value-of select="position()"/>
</Position>
<Field4><xsl:value-of select="field[#id='4']"/></Field4>
<Sum><xsl:value-of select="sum(key('bLine', field[#id='4'])/field[#id='3'])"/></Sum>
</xsl:for-each>
</Line>
</result>
</xsl:template>
</xsl:stylesheet>
You're asking how to group at multiple levels. The following stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="byField2" match="line" use="field[#id='2']" />
<xsl:key name="byField2AndField4" match="line"
use="concat(field[#id='2'], '|', field[#id='4'])" />
<xsl:template match="/">
<document><xsl:apply-templates /></document>
</xsl:template>
<xsl:template
match="line[generate-id() =
generate-id(key('byField2', field[#id='2'])[1])]">
<Result>
<Header>
<Field2><xsl:value-of select="field[#id='2']" /></Field2>
</Header>
<Line>
<xsl:apply-templates
select="key('byField2', field[#id='2'])
[generate-id() =
generate-id(key('byField2AndField4',
concat(field[#id='2'], '|', field[#id='4']))[1])]"
mode="field4" />
</Line>
</Result>
</xsl:template>
<xsl:template match="line" mode="field4">
<Position><xsl:value-of select="position()" /></Position>
<Field4><xsl:value-of select="field[#id='4']" /></Field4>
<Sum>
<xsl:value-of
select="sum(key('byField2AndField4',
concat(field[#id='2'], '|', field[#id='4']))/
field[#id='3'])" />
</Sum>
</xsl:template>
<xsl:template match="line" />
</xsl:stylesheet>
On this input:
<document>
<line id="0">
<field id="2">X111</field>
<field id="3">1</field>
<field id="4">222222222222</field>
</line>
<line id="1">
<field id="2">X111</field>
<field id="3">1</field>
<field id="4">111111111111</field>
</line>
<line id="2">
<field id="2">X222</field>
<field id="3">1</field>
<field id="4">111111111111</field>
</line>
<line id="3">
<field id="2">X222</field>
<field id="3">1></field>
<field id="4">111111111111</field>
</line>
<line id="4">
<field id="2">X333</field>
<field id="3">1</field>
<field id="4">111111111111</field>
</line>
</document>
Produces the desired result:
<document>
<Result>
<Header>
<Field2>X111</Field2>
</Header>
<Line>
<Position>1</Position>
<Field4>222222222222</Field4>
<Sum>1</Sum>
<Position>2</Position>
<Field4>111111111111</Field4>
<Sum>1</Sum>
</Line>
</Result>
<Result>
<Header>
<Field2>X222</Field2>
</Header>
<Line>
<Position>1</Position>
<Field4>111111111111</Field4>
<Sum>2</Sum>
</Line>
</Result>
<Result>
<Header>
<Field2>X333</Field2>
</Header>
<Line>
<Position>1</Position>
<Field4>111111111111</Field4>
<Sum>1</Sum>
</Line>
</Result>
</document>
We use two keys. The first groups only by field 2. The second groups by the concatenation of fields 2 and 4.

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.

Using XSL to get all tags before a tag with given contents occurs

maybe somebody take me some advice how to correct this program. I should take from fields number before +. Sometimes this field comes at the 17th line(field id 17), sometimes 14, 19 and etc...Others fields are also filled. Right now my program takes this number from field id 17. How to correct it?
Data example:
<document>
<line id="0">
<field id="0"><![CDATA[MAR5555]]></field>
<field id="1"><![CDATA[12314124141241]]></field>
<field id="2"><![CDATA[AAS]]></field>
<field id="3"><![CDATA[FOR12312]]></field>
<field id="4"/>
<field id="5"/>
<field id="6"/>
<field id="7"/>
<field id="8"/>
<field id="9"/>
<field id="10"/>
<field id="11"/>
<field id="12"/>
<field id="13"/>
<field id="14"/>
<field id="15"/>
<field id="16"/>
<field id="17"><![CDATA[0072972+1313113123123]]></field>
<field id="18"><![CDATA[5353]]></field>
<field id="19"><![CDATA[444444]]></field>
<field id="20"/>
<field id="21"/>
</line>
<line id="1">
<field id="0"><![CDATA[MAR6435]]></field>
<field id="1"><![CDATA[car123]]></field>
<field id="2"><![CDATA[sds]]></field>
<field id="3"><![CDATA[fest]]></field>
<field id="4"/>
<field id="5"/>
<field id="6"/>
<field id="7"/>
<field id="8"/>
<field id="9"/>
<field id="10"/>
<field id="11"/>
<field id="12"/>
<field id="13"/>
<field id="14"/>
<field id="15"><![CDATA[0000062+0dadasd]]></field>
<field id="16"><![CDATA[0d2]]></field>
<field id="17"><![CDATA[cccc]]></field>
<field id="18"/>
<field id="19"><![CDATA[000000]]></field>
<field id="20"/>
<field id="21"/>
</line>
<line id="2">
<field id="0"><![CDATA[MAR6435]]></field>
<field id="1"><![CDATA[sss]]></field>
<field id="2"><![CDATA[1231231]]></field>
<field id="3"><![CDATA[45123]]></field>
<field id="4"/>
<field id="5"/>
<field id="6"/>
<field id="7"/>
<field id="8"/>
<field id="9"/>
<field id="10"/>
<field id="11"/>
<field id="12"/>
<field id="13"/>
<field id="14"/>
<field id="15"><![CDATA[0000062+0sdsd]]></field>
<field id="16"><![CDATA[0f2]]></field>
<field id="17"><![CDATA[843252dsd]]></field>
<field id="18"/>
<field id="19"><![CDATA[000000]]></field>
<field id="20"/>
<field id="21"/>
</line>
</document>
My program example:
<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-before(field[#id='17'],'+')"/>
<xsl:template match="/*">
<document>
<xsl:apply-templates select="line[contains(field[#id='0'], 'MAR')][count(. | key('kLine', substring-before(field[#id='17'],'+'))[1]) = 1]"/>
</document>
</xsl:template>
<xsl:template match="line">
<type-MAR>
<document>
<xsl:value-of select="substring-before(field[#id='17'],'+')"/>
</document>
</type-MAR>
</xsl:template>
</xsl:stylesheet>
Result:
<type-MAR>
<document>
0072972
</document>
<document>
0000062
</document>
</type-MAR>
<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-before(
field[contains(., '+')]
,'+'
)"/>
<xsl:template match="/*">
<document>
<xsl:apply-templates select="
line
[contains(field[#id='0'], 'MAR')]
[count(
. | key(
'kLine',
substring-before(
field[contains(., '+')]
,'+')
)
[1]
) = 1
]"/>
</document>
</xsl:template>
<xsl:template match="line">
<type-MAR>
<document>
<xsl:value-of select="
substring-before(
field[contains(., '+')],
'+'
)
"/>
</document>
</type-MAR>
</xsl:template>
</xsl:stylesheet>
Well-formed XML output against your sample is:
<document>
<type-MAR>
<document>0072972</document>
</type-MAR>
<type-MAR>
<document>0000062</document>
</type-MAR>
</document>

how to use ELEMENT: xsl:key?

HI all,
I should to generate this xml file:
<document>
<line id="0">
<field id="0"><![CDATA[MAR5555]]></field>
<field id="1"><![CDATA[something]]></field>
<field id="2"><![CDATA[something]]></field>
<field id="3"><![CDATA[something12123]]></field>
<field id="4"/>
<field id="5"/>
<field id="6"/>
<field id="7"/>
<field id="8"/>
<field id="9"/>
<field id="10"/>
<field id="11"/>
<field id="12"/>
<field id="13"/>
<field id="14"/>
<field id="15"/>
<field id="16"/>
<field id="17"><![CDATA[0072972+1313113123123]]></field>
<field id="18"><![CDATA[5353]]></field>
<field id="19"><![CDATA[444432323]]></field>
<field id="20"/>
<field id="21"/>
</line>
<line id="1">
<field id="0"><![CDATA[MAR6435]]></field>
<field id="1"><![CDATA[car123]]></field>
<field id="2"><![CDATA[sds]]></field>
<field id="3"><![CDATA[fest]]></field>
<field id="4"/>
<field id="5"/>
<field id="6"/>
<field id="7"/>
<field id="8"/>
<field id="9"/>
<field id="10"/>
<field id="11"/>
<field id="12"/>
<field id="13"/>
<field id="14"/>
<field id="15"><![CDATA[0000062+0dadasd]]></field>
<field id="16"><![CDATA[032]]></field>
<field id="17"><![CDATA[23242442]]></field>
<field id="18"/>
<field id="19"><![CDATA[000000]]></field>
<field id="20"/>
<field id="21"/>
</line>
<line id="2">
<field id="0"><![CDATA[MAR6435]]></field>
<field id="1"><![CDATA[sss]]></field>
<field id="2"><![CDATA[Something111]]></field>
<field id="3"><![CDATA[something111]]></field>
<field id="4"/>
<field id="5"/>
<field id="6"/>
<field id="7"/>
<field id="8"/>
<field id="9"/>
<field id="10"/>
<field id="11"/>
<field id="12"/>
<field id="13"/>
<field id="14"/>
<field id="15"><![CDATA[0000062+0sdsd]]></field>
<field id="16"><![CDATA[022]]></field>
<field id="17"><![CDATA[23444444]]></field>
<field id="18"/>
<field id="19"><![CDATA[000000]]></field>
<field id="20"/>
<field id="21"/>
</line>
</document>
My programs looks:
<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-before(field[contains(., '+')],'+')"/>
<xsl:template match="/*">
<document>
<xsl:apply-templates select="line[contains(field[#id='0'], 'MAR')][count( . | key('kLine',substring-before(field[contains(., '+')],'+'))[1]) = 1]"/>
</document>
</xsl:template>
<xsl:template match="line">
<type-MAR>
<document>
<xsl:value-of select="substring-before(field[contains(., '+')],'+')"/>
</document>
<!-- For each document-->
<line>
<LineNumber>
<xsl:value-of select="position()"/>
</LineNumber>
<LineItem>
<xsl:value-of select="'should be fielled number of after two fields which contain symbol + '"/>
</LineItem>
</line>
<!-- For each document-->
</type-MAR>
</xsl:template>
</xsl:stylesheet>
I'm stuck, taking LineItem number after field id which contains symbol '+'. for example if I know that 'field id = 17' has + symbol, when after two rows I will have LineItem and do calculating I mean if 'field id = 17' when 'field id = 17+2', if 'field id = 16' then 'field id = 18' and so on. but now when field with symbol '+' are not defining, I can't to do it. Also if I use 'key', i want to ask how to use correct cycle "for each", to calculate number of lines. Result should be:
<document>
<type-MAR>
<document>0072972</document>
<line>
<LineNumber>1</LineNumber>
<LineItem>444432323</LineItem>
</line>
</type-MAR>
<type-MAR>
<document>0000062</document>
<line>
<LineNumber>1</LineNumber>
<LineItem>23242442</LineItem>
<LineNumber>2</LineNumber>
<LineItem>23444444</LineItem>
</line>
</type-MAR>
</document>
I solve it by self. maybe my question was not clearly.
first off all to found path to field after document number I use Following sibling. to select all needed LineItem I use "variable name", finally program looks:
<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-before(field[contains(., '+')],'+')"/>
<xsl:template match="/*">
<document>
<xsl:apply-templates select="line[contains(field[#id='0'], 'MAR')][count( . | key('kLine',substring-before(field[contains(., '+')],'+'))[1]) = 1]"/>
</document>
</xsl:template>
<xsl:template match="line">
<xsl:variable name="doc_code" select="substring-before(field[contains(., '+')],'+')"/>
<type-MAR>
<document>
<xsl:value-of select="substring-before(field[contains(., '+')],'+')"/>
</document>
<xsl:for-each select="//line[substring-before(field[contains(., '+')],'+')=$doc_code]">
<line>
<LineNumber>
<xsl:value-of select="position()"/>
</LineNumber>
<LineItem>
<xsl:value-of select="field[contains(., '+')]/following-sibling::field[2]"/>
</LineItem>
</line>
</xsl:for-each>
</type-MAR>
</xsl:template>
</xsl:stylesheet>
Best regards