Search code examples
xmlxsltxslt-1.0xslt-2.0xslt-3.0

How can I group these ul elements into ul and li elements XSL


Anyone can help me with xsl? I don't know how to achieve this:

This is my sample input xml file:

<?xml version="1.0" encoding="UTF-8"?>
<export>
   <article>
      <h4>Kernpunkte des Discours sind:</h4>
      <ul>eine Erkenntnistheorie, die nur das als richtig akzeptiert, was durch die eigene schrittweise Analyse und logische Reflexion als plausibel verifiziert wird,</ul>
      <ul>eine Ethik, gemäß der das Individuum sich im Sinne bewährter gesellschaftlicher Konventionen pflichtbewusst und moralisch zu verhalten hat,</ul>
      <ul>eine Metaphysik, die zwar (durch logischen Beweis) die Existenz eines vollkommenen Schöpfer-Gottes annimmt, aber kirchenartigen Institutionen wenig Raum lässt,</ul>
      <ul>eine Physik, die die Natur als durch zwar gottgegebene, aber allgemein gültige Gesetze geregelt betrachtet und dem Menschen ihre rationale Erklärung und damit letztlich ihre Beherrschung zur Aufgabe macht.</ul>
   </article>
</export>

I need to group all <ul> elements into <ul><li>…</li></ul> elements so that it will become like this:

<?xml version="1.0" encoding="UTF-8"?>
<export>
   <article>
      <h4>Kernpunkte des Discours sind:</h4>
      <ul>
         <li>eine Erkenntnistheorie, die nur das als richtig akzeptiert, was durch die eigene schrittweise Analyse und logische Reflexion als plausibel verifiziert wird,</li>
         <li>eine Ethik, gemäß der das Individuum sich im Sinne bewährter gesellschaftlicher Konventionen pflichtbewusst und moralisch zu verhalten hat,</li>
         <li>eine Metaphysik, die zwar (durch logischen Beweis) die Existenz eines vollkommenen Schöpfer-Gottes annimmt, aber kirchenartigen Institutionen wenig Raum lässt,</li>
         <li>eine Physik, die die Natur als durch zwar gottgegebene, aber allgemein gültige Gesetze geregelt betrachtet und dem Menschen ihre rationale Erklärung und damit letztlich ihre Beherrschung zur Aufgabe macht.</li>
      </ul>
   </article>
</export>

I tried something like this:

<?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" indent="yes" />

  <xsl:template match="/">
    <export>
      <article>
        <xsl:apply-templates />
      </article>
    </export>
  </xsl:template>

  <xsl:template match="ul">
    <ul>
      <xsl:apply-templates />
    </ul>
  </xsl:template>

  <xsl:template match="ul/text()">
    <li>
      <xsl:value-of select="." />
    </li>
  </xsl:template>

</xsl:stylesheet>

But it does not work as expected:

<?xml version="1.0" encoding="UTF-8"?>
<export>
   <article>
      Kernpunkte des Discours sind:
      <ul>
         <li>eine Erkenntnistheorie, die nur das als richtig akzeptiert, was durch die eigene schrittweise Analyse und logische Reflexion als plausibel verifiziert wird,</li>
      </ul>
      <ul>
         <li>eine Ethik, gemäß der das Individuum sich im Sinne bewährter gesellschaftlicher Konventionen pflichtbewusst und moralisch zu verhalten hat,</li>
      </ul>
      <ul>
         <li>eine Metaphysik, die zwar (durch logischen Beweis) die Existenz eines vollkommenen Schöpfer-Gottes annimmt, aber kirchenartigen Institutionen wenig Raum lässt,</li>
      </ul>
      <ul>
         <li>eine Physik, die die Natur als durch zwar gottgegebene, aber allgemein gültige Gesetze geregelt betrachtet und dem Menschen ihre rationale Erklärung und damit letztlich ihre Beherrschung zur Aufgabe macht.</li>
      </ul>
   </article>
</export>

Can someone who is very good with xsl help me with my request?

Thanks in advance!

Regards, Noel


Solution

  • I would try this way:

    <xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="article">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="name()"> 
                <xsl:choose>
                    <xsl:when test="self::ul">
                        <ul>
                            <xsl:apply-templates select="current-group()"/>
                        </ul>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ul">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
    
    </xsl:stylesheet>
    

    This is in XSLT 3.0.


    If article has only h4 and ul child elements, then you can do only:

    <xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="article">
        <xsl:copy>
            <xsl:apply-templates select="h4"/>
            <ul>
                <xsl:apply-templates select="ul"/>
            </ul>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ul">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>
    
    </xsl:stylesheet>