Stumped - Need XSLT Help

Discussion in 'XML' started by J, Sep 12, 2006.

  1. J

    J Guest

    I've spent most of the day on this, and I just can't seem to find a
    solution, please help me! :)

    I'm recieving XML that I can't modify that looks like:

    <?xml version="1.0"?>
    <Doc>
    <Page>
    <Item Value="A" Id="1" Count="1"/>
    <Item Value="B" Id="2" Count="1"/>
    <Item Value="C" Id="3" Count="1"/>
    <Item Value="D" Id="1" Count="2"/>
    <Item Value="E" Id="2" Count="2"/>
    <Item Value="F" Id="3" Count="2"/>
    <Item Value="G" Id="1" Count="3"/>
    <Item Value="H" Id="2" Count="3"/>
    <Item Value="I" Id="3" Count="3"/>
    </Page>
    </Doc>


    And I need to transform it into:

    <Doc>
    <Page>
    <Line>
    <Tag1>A</Tag1>
    <Tag2>B</Tag2>
    <Tag3>C</Tag3>
    </Line>
    <Line>
    <Tag1>D</Tag1>
    <Tag2>E</Tag2>
    <Tag3>F</Tag3>
    </Line>
    <Line>
    <Tag1>G</Tag1>
    <Tag2>H</Tag2>
    <Tag3>I</Tag3>
    </Line>
    </Page>
    </Doc>

    But I can't seem to figure out how to create a new "Line" node based on
    the count attribute.

    Here is XSLT I have now:


    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="xml" />

    <xsl:template match="Doc">
    <Doc>
    <xsl:apply-templates select="Page"/>
    </Doc>
    </xsl:template>

    <xsl:template match="Page">
    <Page>
    <Line>
    <xsl:for-each select="Item">

    <xsl:if test="@Id='1'">
    <Tag1><xsl:value-of select="@Value"/></Tag1>
    </xsl:if>
    <xsl:if test="@Id='2'">
    <Tag2><xsl:value-of select="@Value"/></Tag2>
    </xsl:if>
    <xsl:if test="@Id='3'">
    <Tag3><xsl:value-of select="@Value"/></Tag3>
    </xsl:if>

    </xsl:for-each>
    </Line>
    </Page>
    </xsl:template>
    </xsl:stylesheet>


    Which only produces:

    <Doc>
    <Page>
    <Line>
    <Tag1>A</Tag1>
    <Tag2>B</Tag2>
    <Tag3>C</Tag3>
    <Tag1>D</Tag1>
    <Tag2>E</Tag2>
    <Tag3>F</Tag3>
    <Tag1>G</Tag1>
    <Tag2>H</Tag2>
    <Tag3>I</Tag3>
    </Line>
    </Page>
    </Doc>


    Any help at all is warmly welcomed!
     
    J, Sep 12, 2006
    #1
    1. Advertising

  2. Read about and use the XPath "mod" operator


    Cheers,
    Dimitre Novatchev


    "J" <> wrote in message
    news:...
    > I've spent most of the day on this, and I just can't seem to find a
    > solution, please help me! :)
    >
    > I'm recieving XML that I can't modify that looks like:
    >
    > <?xml version="1.0"?>
    > <Doc>
    > <Page>
    > <Item Value="A" Id="1" Count="1"/>
    > <Item Value="B" Id="2" Count="1"/>
    > <Item Value="C" Id="3" Count="1"/>
    > <Item Value="D" Id="1" Count="2"/>
    > <Item Value="E" Id="2" Count="2"/>
    > <Item Value="F" Id="3" Count="2"/>
    > <Item Value="G" Id="1" Count="3"/>
    > <Item Value="H" Id="2" Count="3"/>
    > <Item Value="I" Id="3" Count="3"/>
    > </Page>
    > </Doc>
    >
    >
    > And I need to transform it into:
    >
    > <Doc>
    > <Page>
    > <Line>
    > <Tag1>A</Tag1>
    > <Tag2>B</Tag2>
    > <Tag3>C</Tag3>
    > </Line>
    > <Line>
    > <Tag1>D</Tag1>
    > <Tag2>E</Tag2>
    > <Tag3>F</Tag3>
    > </Line>
    > <Line>
    > <Tag1>G</Tag1>
    > <Tag2>H</Tag2>
    > <Tag3>I</Tag3>
    > </Line>
    > </Page>
    > </Doc>
    >
    > But I can't seem to figure out how to create a new "Line" node based on
    > the count attribute.
    >
    > Here is XSLT I have now:
    >
    >
    > <?xml version="1.0" encoding="UTF-8" ?>
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:eek:utput method="xml" />
    >
    > <xsl:template match="Doc">
    > <Doc>
    > <xsl:apply-templates select="Page"/>
    > </Doc>
    > </xsl:template>
    >
    > <xsl:template match="Page">
    > <Page>
    > <Line>
    > <xsl:for-each select="Item">
    >
    > <xsl:if test="@Id='1'">
    > <Tag1><xsl:value-of select="@Value"/></Tag1>
    > </xsl:if>
    > <xsl:if test="@Id='2'">
    > <Tag2><xsl:value-of select="@Value"/></Tag2>
    > </xsl:if>
    > <xsl:if test="@Id='3'">
    > <Tag3><xsl:value-of select="@Value"/></Tag3>
    > </xsl:if>
    >
    > </xsl:for-each>
    > </Line>
    > </Page>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    >
    > Which only produces:
    >
    > <Doc>
    > <Page>
    > <Line>
    > <Tag1>A</Tag1>
    > <Tag2>B</Tag2>
    > <Tag3>C</Tag3>
    > <Tag1>D</Tag1>
    > <Tag2>E</Tag2>
    > <Tag3>F</Tag3>
    > <Tag1>G</Tag1>
    > <Tag2>H</Tag2>
    > <Tag3>I</Tag3>
    > </Line>
    > </Page>
    > </Doc>
    >
    >
    > Any help at all is warmly welcomed!
    >
     
    Dimitre Novatchev, Sep 13, 2006
    #2
    1. Advertising

  3. J

    George Bina Guest

    Hi,

    You can match on the first Item, then create a Line element and put
    inside the output for all the items with the same Count value and then
    apply match on the Item with the next count value, create again a Line
    element and place inside the output for the Item elements with the same
    Count value and so on, see

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput indent="yes"/>
    <xsl:template match="/">
    <Doc><Page><xsl:apply-templates
    select="Doc/Page/Item[1]"/></Page></Doc>
    </xsl:template>
    <xsl:template match="Item">
    <Line>
    <xsl:apply-templates select="../Item[@Count=current()/@Count]"
    mode="print"/>
    </Line>
    <xsl:apply-templates
    select="../Item[@Count=1+current()/@Count][1]"/>
    </xsl:template>
    <xsl:template match="Item" mode="print">
    <xsl:element name="Tag{@Id}"><xsl:value-of
    select="@Value"/></xsl:element>
    </xsl:template>
    </xsl:stylesheet>

    Best Regards,
    George
    ---------------------------------------------------------------------
    George Cristian Bina
    <oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
    http://www.oxygenxml.com



    J wrote:
    > I've spent most of the day on this, and I just can't seem to find a
    > solution, please help me! :)
    >
    > I'm recieving XML that I can't modify that looks like:
    >
    > <?xml version="1.0"?>
    > <Doc>
    > <Page>
    > <Item Value="A" Id="1" Count="1"/>
    > <Item Value="B" Id="2" Count="1"/>
    > <Item Value="C" Id="3" Count="1"/>
    > <Item Value="D" Id="1" Count="2"/>
    > <Item Value="E" Id="2" Count="2"/>
    > <Item Value="F" Id="3" Count="2"/>
    > <Item Value="G" Id="1" Count="3"/>
    > <Item Value="H" Id="2" Count="3"/>
    > <Item Value="I" Id="3" Count="3"/>
    > </Page>
    > </Doc>
    >
    >
    > And I need to transform it into:
    >
    > <Doc>
    > <Page>
    > <Line>
    > <Tag1>A</Tag1>
    > <Tag2>B</Tag2>
    > <Tag3>C</Tag3>
    > </Line>
    > <Line>
    > <Tag1>D</Tag1>
    > <Tag2>E</Tag2>
    > <Tag3>F</Tag3>
    > </Line>
    > <Line>
    > <Tag1>G</Tag1>
    > <Tag2>H</Tag2>
    > <Tag3>I</Tag3>
    > </Line>
    > </Page>
    > </Doc>
    >
    > But I can't seem to figure out how to create a new "Line" node based on
    > the count attribute.
    >
    > Here is XSLT I have now:
    >
    >
    > <?xml version="1.0" encoding="UTF-8" ?>
    > <xsl:stylesheet version="1.0"
    > xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    > <xsl:eek:utput method="xml" />
    >
    > <xsl:template match="Doc">
    > <Doc>
    > <xsl:apply-templates select="Page"/>
    > </Doc>
    > </xsl:template>
    >
    > <xsl:template match="Page">
    > <Page>
    > <Line>
    > <xsl:for-each select="Item">
    >
    > <xsl:if test="@Id='1'">
    > <Tag1><xsl:value-of select="@Value"/></Tag1>
    > </xsl:if>
    > <xsl:if test="@Id='2'">
    > <Tag2><xsl:value-of select="@Value"/></Tag2>
    > </xsl:if>
    > <xsl:if test="@Id='3'">
    > <Tag3><xsl:value-of select="@Value"/></Tag3>
    > </xsl:if>
    >
    > </xsl:for-each>
    > </Line>
    > </Page>
    > </xsl:template>
    > </xsl:stylesheet>
    >
    >
    > Which only produces:
    >
    > <Doc>
    > <Page>
    > <Line>
    > <Tag1>A</Tag1>
    > <Tag2>B</Tag2>
    > <Tag3>C</Tag3>
    > <Tag1>D</Tag1>
    > <Tag2>E</Tag2>
    > <Tag3>F</Tag3>
    > <Tag1>G</Tag1>
    > <Tag2>H</Tag2>
    > <Tag3>I</Tag3>
    > </Line>
    > </Page>
    > </Doc>
    >
    >
    > Any help at all is warmly welcomed!
     
    George Bina, Sep 13, 2006
    #3
  4. J

    Guest

    J wrote:
    > I've spent most of the day on this, and I just can't seem
    > to find a solution, please help me! :)
    >
    > I'm recieving XML that I can't modify that looks like:
    >
    > <?xml version="1.0"?>
    > <Doc>
    > <Page>
    > <Item Value="A" Id="1" Count="1"/>
    > <Item Value="B" Id="2" Count="1"/>
    > <Item Value="C" Id="3" Count="1"/>
    > <Item Value="D" Id="1" Count="2"/>
    > <Item Value="E" Id="2" Count="2"/>
    > <Item Value="F" Id="3" Count="2"/>
    > <Item Value="G" Id="1" Count="3"/>
    > <Item Value="H" Id="2" Count="3"/>
    > <Item Value="I" Id="3" Count="3"/>
    > </Page>
    > </Doc>
    >
    > And I need to transform it into:


    [<Item>s grouped into <Line>s by Count attribute]

    I'm not an XSLT expert, just toying with it in my spare
    time, so there are probably much better solutions to your
    problem; nevertheless, the following XSLT seems to produce
    the results you need:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput
    method="xml"
    version="1.0"
    encoding="UTF-8"/>
    <xsl:template match="/Doc">
    <Doc>
    <xsl:apply-templates select="./Page"/>
    </Doc>
    </xsl:template>
    <xsl:template match="Page">
    <Page>
    <xsl:apply-templates select="./Item">
    <xsl:with-param name="l">1</xsl:with-param>
    </xsl:apply-templates>
    </Page>
    </xsl:template>
    <xsl:template match="Item">
    <xsl:param name="l"/>
    <xsl:choose>
    <xsl:when test="$l='0'">
    <xsl:choose>
    <xsl:when test="@Id='1'">
    <Tag1><xsl:value-of select="@Value"/></Tag1>
    </xsl:when>
    <xsl:when test="@Id='2'">
    <Tag2><xsl:value-of select="@Value"/></Tag2>
    </xsl:when>
    <xsl:when test="@Id='3'">
    <Tag3><xsl:value-of select="@Value"/></Tag3>
    </xsl:when>
    </xsl:choose>
    </xsl:when>
    <xsl:when test="$l!='0'">
    <xsl:if
    test="
    starts-with(
    generate-id(//Item[@Count=current()/@Count]),
    generate-id(.))">
    <Line>
    <xsl:apply-templates
    select="../Item[@Count=current()/@Count]">
    <xsl:with-param name="l">0</xsl:with-param>
    </xsl:apply-templates>
    </Line>
    </xsl:if>
    </xsl:when>
    </xsl:choose>
    </xsl:template>
    </xsl:stylesheet>

    --
    Pavel Lepin
     
    , Sep 13, 2006
    #4
  5. J

    J Guest

    Thanks for the responses all.

    I stayed up late and found a way to do it with a grouping key.


    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="xml" />

    <xsl:key name="line-by-count" match="Item" use="@Count"/>

    <xsl:template match="Doc">
    <Doc>
    <xsl:apply-templates select="Page"/>
    </Doc>
    </xsl:template>


    <xsl:template match="Page">
    <Page>
    <xsl:for-each
    select="Item[count(.|key('line-by-count',@Count)[1])=1]">
    <Line>
    <xsl:for-each select="key('line-by-count',@Count)">
    <xsl:if test="@Id='1'">
    <Tag1><xsl:value-of select="@Value"/></Tag1>
    </xsl:if>
    <xsl:if test="@Id='2'">
    <Tag2><xsl:value-of select="@Value"/></Tag2>
    </xsl:if>
    <xsl:if test="@Id='3'">
    <Tag3><xsl:value-of select="@Value"/></Tag3>
    </xsl:if>
    </xsl:for-each>
    </Line>
    </xsl:for-each>
    </Page>
    </xsl:template>
    </xsl:stylesheet>
     
    J, Sep 13, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Harri
    Replies:
    0
    Views:
    353
    Harri
    Dec 20, 2004
  2. PBR

    Stumped on this XSLT

    PBR, Oct 5, 2004, in forum: XML
    Replies:
    1
    Views:
    381
    David Carlisle
    Oct 5, 2004
  3. Replies:
    2
    Views:
    494
    David Carlisle
    Feb 1, 2005
  4. Replies:
    35
    Views:
    2,321
  5. john
    Replies:
    10
    Views:
    321
    Andreas Leitgeb
    Dec 19, 2013
Loading...

Share This Page