![]() |
|
|
|
#1 |
|
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 <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 |
|
|
|
|
#2 |
|
Posts: n/a
|
Read about and use the XPath "mod" operator
Cheers, Dimitre Novatchev "J" <> wrote in message news: ups.com... > 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 > > <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! > |
|
|
|
#3 |
|
Posts: n/a
|
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 <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 > > <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! |
|
|
|
#4 |
|
Posts: n/a
|
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 version="1.0"> <xsl 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 <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 |
|
|
|
#5 |
|
Posts: n/a
|
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 <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> |
|