Group contiguous elements using XSLT 1.0

I hope to get some tips on how to group adjacent elements of the same name in an unordered list using XSLT 1.0.

Here is an example XML:

<Article>
  <TextContent>
    <p>lorem</p>
    <VisualContent id="1" />
    <VisualContent id="2" />
    <VisualContent id="3" />
    <p>ipsum</p>
    <VisualContent id="4" />
    <p>dolor</p>
    <VisualContent id="5" />
  </TextContent>
</Article>

Here's the output I need:

<Article>
  <HtmlContent>
    <p>lorem</p>
    <ul>
      <li><img data-id="1" /></li>
      <li><img data-id="2" /></li>
      <li><img data-id="3" /></li>
    </ul>
    <p>ipsum</p>
    <img data-id="4" />
    <p>dolor</p>
    <img data-id="5" />
  </HtmlContent>
</Article>

Unfortunately, XSLT 1.0 is a strict requirement for this. Any suggestions would be greatly appreciated.

0
source share
3 answers

I missed the part in which it <TextContent>turns into <HtmlContent>, but <VisualContent id="n" />becomes <img data-id="n" />, because this question is quite difficult without these distracting factors.

, . - , :

<?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" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:key name="prevByName" match="TextContent/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" />

<xsl:template match="/">
<Article><TextContent>
    <xsl:for-each select="Article/TextContent/*[generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])]">
        <xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" />
        <xsl:choose>
            <xsl:when test="count($myGroup) > 1">
                <ul>
                    <xsl:for-each select="$myGroup">
                    <li><xsl:copy-of select="."/></li>
                    </xsl:for-each>
                </ul>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</TextContent></Article>
</xsl:template>
</xsl:stylesheet>

:

<?xml version="1.0" encoding="utf-8"?>
<Article>
   <TextContent>
      <p>lorem</p>
      <ul>
         <li>
            <VisualContent id="1"/>
         </li>
         <li>
            <VisualContent id="2"/>
         </li>
         <li>
            <VisualContent id="3"/>
         </li>
      </ul>
      <p>ipsum</p>
      <VisualContent id="4"/>
      <p>dolor</p>
      <VisualContent id="5"/>
   </TextContent>
</Article>

EDIT: , "VisualContent":

<?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" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:key name="prevByName" match="TextContent/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" />

<xsl:template match="/Article/TextContent">
    <Article><TextContent>
        <xsl:apply-templates select="*"/>
    </TextContent></Article>
</xsl:template>

<xsl:template match="TextContent/*[not(self::VisualContent)]">
    <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="VisualContent[generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])]">
<xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" />
    <xsl:choose>
        <xsl:when test="count($myGroup) > 1">
            <ul>
                <xsl:for-each select="$myGroup">
                <li><xsl:copy-of select="."/></li>
                </xsl:for-each>
            </ul>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

, - , , , ...

+2

XSLT.

, <ul>, , . .

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" encoding="UTF-8" />
    <xsl:template match="/">
        <Article>
            <HtmlContent>
                <xsl:apply-templates />
            </HtmlContent>
        </Article>
    </xsl:template>

    <xsl:template match="VisualContent">
        <li>
            <xsl:element name="img">
                <xsl:attribute name="date-id"><xsl:number/></xsl:attribute>
            </xsl:element>
        </li>
    </xsl:template>

    <xsl:template match="p">
        <xsl:element name="p">
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

:

<Article>
    <HtmlContent>
        <p>lorem</p>
        <li><img date-id="1" /></li>
        <li><img date-id="2" /></li>
        <li><img date-id="3" /></li>
        <p>ipsum</p>
        <li><img date-id="4" /></li>
        <p>dolor</p>
        <li><img date-id="5" /></li>
    </HtmlContent>
</Article>
0

, xsltproc (1.1.29), . TextContent, .

:

<Article>
    <TextContent>
        <p>lorem</p>
        <VisualContent id="1" />
        <VisualContent id="2" />
        <VisualContent id="3" />
        <p>ipsum</p>
        <VisualContent id="4" />
        <p>dolor</p>
        <p>sit</p>
        <VisualContent id="5" />
    </TextContent>
    <p>amet</p>
    <VisualContent id="6" />
    <VisualContent id="7" />
    <p>consectetur</p>
    <VisualContent id="8" />
</Article>

:

<?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" version="1.0" encoding="utf-8" indent="yes"/>

    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:key name="prevByName" match="*/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" />

    <xsl:template match="VisualContent">
        <xsl:if test="generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])">
            <xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" />
            <xsl:choose>
                <xsl:when test="count($myGroup) > 1">
                    <ul>
                        <xsl:for-each select="$myGroup">
                            <li>
                                <xsl:copy-of select="."/>
                            </li>
                        </xsl:for-each>
                    </ul>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

.: -)

<?xml version="1.0" encoding="utf-8"?>
<Article>
    <TextContent>
        <p>lorem</p>
        <ul><li><VisualContent id="1"/></li><li><VisualContent id="2"/></li><li><VisualContent id="3"/></li></ul>


        <p>ipsum</p>
        <VisualContent id="4"/>
        <p>dolor</p>
        <p>sit</p>
        <VisualContent id="5"/>
    </TextContent>
    <p>amet</p>
    <ul><li><VisualContent id="6"/></li><li><VisualContent id="7"/></li></ul>

    <p>consectetur</p>
    <VisualContent id="8"/>
</Article>
0
source

All Articles