0
votes

I have the following xml pattern :

<tag name="(some_string)_start">
<tag name="step1">
<tag name="step2">
<tag name="step3">
<tag name="step4">
<tag name="(some_string)_end">
<tag name="(some_other_string)_start">
<tag name="step1">
<tag name="step2">
<tag name="step3">
<tag name="step4">
<tag name="step5">
<tag name="(some_other_string)_end">

I need to transform it to a text file as follows using XSLT:

name=(some_string), step_index=0
name=step1, step_index=1
name=step2, step_index=2
name=step3, step_index=3
name=step4, step_index=4
name=(some_string), step_index=5
name=(some_other_string), step_index=0
name=step1, step_index=1
name=step2, step_index=2
name=step3, step_index=3
name=step4, step_index=4
name=step5, step_index=5
name=(some_other_string), step_index=6

I want to count the number of nodes starting with suffix 'start' to 'end' When i encounter next name with suffix 'start', counter should be reinitialized to zero

Following is the XSLT I tried :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">    
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
    <xsl:accumulator name="step-index" initial-value="0">
        <xsl:accumulator-rule match="sample[matches(@name, '.*Start$')]" select="0">
        </xsl:accumulator-rule>
        <xsl:accumulator-rule match="sample[matches(@name, '.*End$')]" select="$value+1">
        </xsl:accumulator-rule>         
    </xsl:accumulator>
    <xsl:template match="tag">
        <xsl:text>,name=</xsl:text>
        <xsl:value-of select="@name"/>
        <xsl:text>,step-index=</xsl:text>
            <xsl:value-of select="accumulator-after('step-index')"/>
    </xsl:template>
</xsl:stylesheet>

But I dont get the desired output using the above accumulator method. How do I compute the step_index value using XSLT?

Thanks in advance!

1
"But I dont get the desired output ": can you at least explain which tool you use and which error or wrong output you get? accumulators were introduced in XSLT 3.0 so a question tagged as xslt-2.0 trying to use accumulators and telling "I don't get the desired output" begs the question whether you really have an XSLT 3 processor. Your code seems to lack <xsl:mode use-accumulators="#all"/> or <xsl:mode use-accumulators="step-index"/> for a start. - Martin Honnen
It is also not clear whether your input XML has nested tag elements or sibling tag elements. - Martin Honnen
Sorry for that. I just tried to give a sample input, output and xslt. I do use <xsl:mode use-accumulators> tag in my actual XSLT.Also I am trying to do the conversion using Ant Script. I dont know whether this could be achieved through some other way or using accumulator. My requirement is to increment the counter when i enounter a tag with suffix 'start' until i encounter another tag with attribute suffix value 'end'. Any suggestions would be much appreciated. - code-geek
Also my input xml does not have nested tag. All are the child elements of root xml tag only. - code-geek

1 Answers

1
votes

As I said in a comment, you have not explained how your approach fails exactly and whether you at least try to run that XSLT 3 feature with an XSLT 3 processor.

A minimal sample would be

<?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="#all"
    expand-text="yes"
    version="3.0">
    
    <xsl:mode use-accumulators="step-index"/>

    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:accumulator name="step-index" initial-value="0">
        <xsl:accumulator-rule match="tag[ends-with(@name, '_start')]" select="0"/>
        <xsl:accumulator-rule match="tag[not(ends-with(@name, '_start'))]" select="$value + 1"/>
    </xsl:accumulator>
    
    <xsl:template match="tag">
        <xsl:text>name={@name => replace('_(start|end)$', '')},step-index={accumulator-after('step-index')}&#10;</xsl:text>
    </xsl:template>
  
</xsl:stylesheet>

Run at https://xsltfiddle.liberty-development.net/ehW12fW/1 with Saxon 9.8 HE against a well-formed sample

<root>
<tag name="(some_string)_start"/>
<tag name="step1"/>
<tag name="step2"/>
<tag name="step3"/>
<tag name="step4"/>
<tag name="(some_string)_end"/>
<tag name="(some_other_string)_start"/>
<tag name="step1"/>
<tag name="step2"/>
<tag name="step3"/>
<tag name="step4"/>
<tag name="step5"/>
<tag name="(some_other_string)_end"/>
</root>

it outputs

name=(some_string),step-index=0
name=step1,step-index=1
name=step2,step-index=2
name=step3,step-index=3
name=step4,step-index=4
name=(some_string),step-index=5
name=(some_other_string),step-index=0
name=step1,step-index=1
name=step2,step-index=2
name=step3,step-index=3
name=step4,step-index=4
name=step5,step-index=5
name=(some_other_string),step-index=6