admin管理员组

文章数量:1023758

It has been awhile since I coded, and a friend has asked me for help. I can't seem to get my head around it. It's old code I'm trying to fix up.

Basically, I'm trying to make a table that indents for each child of the parent.

I can get it to indent the first child correctly, then it stops. Can someone kindly point in the direction of where I can read up on this?

*Update

I have added code as best as I can atm. Adding during break at work. Will update more if needed after work.

Data - Values have been changes because I've been feeling snackish.

<foods>
    <name>Junk Food</name>
    <qty>1</qty>
    <children>
        <food>
            <name>Gummies</name>
            <qty>7</qty>
            <children>
                <food>
                    <name>Chocolate</name>
                    <qty>5</qty>
                    <children />
                </food>
            </children>
            <children>
                <food>
                    <name>Sour</name>
                    <qty>2</qty>
                    <children />
                </food>
            </children>
        <food>
            <name>Chips</name>
            <qty>8</qty>
            <children>
                <food>
                    <name>Salt & Vinegar</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Lightly Salted</name>
                    <qty>1</qty>
                    <children>
                        <food>
                            <name>Rippled</name>
                            <qty>2</qty>
                            <children>
                        </food>
                    </children>
                </food>
            <children />
        </food>
        <food>
            <name>Fruit</name>
            <qty>18</qty>
            <children>
                <food>
                    <name>Pineapple</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Apple</name>
                    <qty>13</qty>
                    <children>
                        <food>
                        <name>Macintosh</name>
                        <qty>8</qty>
                        <children />
                        </food>
                        <food>
                        <name>Golden</name>
                        <qty>2</qty>
                        <children />
                        </food>
                        <food>
                        <name>Granny Smith</name>
                        <qty>3</qty>
                        <children />
                        </food>
                    </children>
                </food>
            </children>
        </food>
    </children>
</foods>

**Code **

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Character sheet based on the Shadowrun 4th Edition Character Sheet -->
<!-- Created by Keith Rudolph, [email protected] -->
<!-- Version -892 -->
<xsl:stylesheet version="1.0" xmlns:xsl="; xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:include href="ConditionMonitor.xslt"/>
    <xsl:template match="/characters/character">
        <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ".dtd">]]></xsl:text>
        <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
                <title><xsl:value-of select="name" /></title>
                <style type="text/css">
                    *
                    {
                        font-family: segoe condensed, tahoma, trebuchet ms, arial;
                        font-size: 8pt;
                        text-align: left;
                    }
                    .tableborder
                    {
                        border: solid 2px #1c4a2d;
                    }
                    .indent
                    {
                        padding-left: 20px;
                    }
                </style>
            </head>
            <body>

<div class="block" id="foodBlock">
    <table width="100%" cellspacing="0" cellpadding="0" border="0">
        <tr><td width="70%" class="tableborder" style="text-align:center;" valign="top">

                            <table width="100%" cellspacing="0" cellpadding="0" border="0">
                                <tr>
                                    <td width="55%">
                                        <strong>NAME</strong>
                                    </td>
                                    <td width="15%" style="text-align:center;">
                                        <strong>QTY.</strong>
                                    </td>
                                </tr>
                                <xsl:call-template name="food1" />
                            </table>
                        </td>
                    </tr>
                </table>
            </div>


<xsl:template name="foodplugin">
    <xsl:param name="food" />
    <xsl:for-each select="children/food">
        <xsl:sort select="name" />
        <xsl:sort select="foodname" />
        <xsl:value-of select="qty" /><xsl:text>x </xsl:text>
        <xsl:value-of select="name" />
        <xsl:if test="children/food">
            <br /><xsl:text>&#160;&#160;</xsl:text>
            <xsl:call-template name="foodplugin">
                <xsl:with-param name="food" select="." />
            </xsl:call-template>
        </xsl:if>
        <xsl:if test="position() != last()"><br /></xsl:if>
    </xsl:for-each>
</xsl:template>

<xsl:template name="food1">
        <xsl:variable name="halfcut" select="count(foods/food)"/>
        <xsl:variable name="sortedcopy">
            <xsl:for-each select="foods/food">
                <xsl:sort select="food" />
                <xsl:sort select="name" />
                <xsl:if test="position() &lt;= $halfcut">
                    <xsl:copy-of select="current()"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
        <xsl:for-each select="msxsl:node-set($sortedcopy)/food">
            <xsl:choose>
                <xsl:when test="position() = 1">
                    <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:choose>
                        <xsl:when test="location != preceding-sibling::food[1]/location">
                                        <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                        </xsl:when>
                    </xsl:choose>
                </xsl:otherwise>
            </xsl:choose>
            <tr>
                <xsl:if test="position() mod 2 != 1">
                    <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                </xsl:if>
                <td width="80%" valign="top">
                    <xsl:value-of select="name" />
                </td>
                <td width="10%" style="text-align:center;" valign="top">
                    <xsl:choose>
                        <xsl:when test="children/food != ''"> </xsl:when>
                        <xsl:otherwise><xsl:value-of select="qty" /></xsl:otherwise>
                    </xsl:choose>
                </td>
            </tr>
            <xsl:if test="children/food">
                <tr>
                    <xsl:if test="position() mod 2 != 1">
                        <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                    </xsl:if>
                    <td colspan="3" class="indentfood">
                        <xsl:call-template name="foodplugin">
                            <xsl:with-param name="food" select="." />
                        </xsl:call-template>
                    </td>
                </tr>
            </xsl:if>
          </xsl:for-each>
    </body>
    </html>
</xsl:template>

Desired

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
        Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
            BC
            California
        Golden
        Macintosh

Result

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
    Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
        BC
    California
    Golden
    Macintosh

It has been awhile since I coded, and a friend has asked me for help. I can't seem to get my head around it. It's old code I'm trying to fix up.

Basically, I'm trying to make a table that indents for each child of the parent.

I can get it to indent the first child correctly, then it stops. Can someone kindly point in the direction of where I can read up on this?

*Update

I have added code as best as I can atm. Adding during break at work. Will update more if needed after work.

Data - Values have been changes because I've been feeling snackish.

<foods>
    <name>Junk Food</name>
    <qty>1</qty>
    <children>
        <food>
            <name>Gummies</name>
            <qty>7</qty>
            <children>
                <food>
                    <name>Chocolate</name>
                    <qty>5</qty>
                    <children />
                </food>
            </children>
            <children>
                <food>
                    <name>Sour</name>
                    <qty>2</qty>
                    <children />
                </food>
            </children>
        <food>
            <name>Chips</name>
            <qty>8</qty>
            <children>
                <food>
                    <name>Salt & Vinegar</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Lightly Salted</name>
                    <qty>1</qty>
                    <children>
                        <food>
                            <name>Rippled</name>
                            <qty>2</qty>
                            <children>
                        </food>
                    </children>
                </food>
            <children />
        </food>
        <food>
            <name>Fruit</name>
            <qty>18</qty>
            <children>
                <food>
                    <name>Pineapple</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Apple</name>
                    <qty>13</qty>
                    <children>
                        <food>
                        <name>Macintosh</name>
                        <qty>8</qty>
                        <children />
                        </food>
                        <food>
                        <name>Golden</name>
                        <qty>2</qty>
                        <children />
                        </food>
                        <food>
                        <name>Granny Smith</name>
                        <qty>3</qty>
                        <children />
                        </food>
                    </children>
                </food>
            </children>
        </food>
    </children>
</foods>

**Code **

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Character sheet based on the Shadowrun 4th Edition Character Sheet -->
<!-- Created by Keith Rudolph, [email protected] -->
<!-- Version -892 -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3./1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:include href="ConditionMonitor.xslt"/>
    <xsl:template match="/characters/character">
        <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3./TR/xhtml1/DTD/xhtml1-strict.dtd">]]></xsl:text>
        <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
                <title><xsl:value-of select="name" /></title>
                <style type="text/css">
                    *
                    {
                        font-family: segoe condensed, tahoma, trebuchet ms, arial;
                        font-size: 8pt;
                        text-align: left;
                    }
                    .tableborder
                    {
                        border: solid 2px #1c4a2d;
                    }
                    .indent
                    {
                        padding-left: 20px;
                    }
                </style>
            </head>
            <body>

<div class="block" id="foodBlock">
    <table width="100%" cellspacing="0" cellpadding="0" border="0">
        <tr><td width="70%" class="tableborder" style="text-align:center;" valign="top">

                            <table width="100%" cellspacing="0" cellpadding="0" border="0">
                                <tr>
                                    <td width="55%">
                                        <strong>NAME</strong>
                                    </td>
                                    <td width="15%" style="text-align:center;">
                                        <strong>QTY.</strong>
                                    </td>
                                </tr>
                                <xsl:call-template name="food1" />
                            </table>
                        </td>
                    </tr>
                </table>
            </div>


<xsl:template name="foodplugin">
    <xsl:param name="food" />
    <xsl:for-each select="children/food">
        <xsl:sort select="name" />
        <xsl:sort select="foodname" />
        <xsl:value-of select="qty" /><xsl:text>x </xsl:text>
        <xsl:value-of select="name" />
        <xsl:if test="children/food">
            <br /><xsl:text>&#160;&#160;</xsl:text>
            <xsl:call-template name="foodplugin">
                <xsl:with-param name="food" select="." />
            </xsl:call-template>
        </xsl:if>
        <xsl:if test="position() != last()"><br /></xsl:if>
    </xsl:for-each>
</xsl:template>

<xsl:template name="food1">
        <xsl:variable name="halfcut" select="count(foods/food)"/>
        <xsl:variable name="sortedcopy">
            <xsl:for-each select="foods/food">
                <xsl:sort select="food" />
                <xsl:sort select="name" />
                <xsl:if test="position() &lt;= $halfcut">
                    <xsl:copy-of select="current()"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
        <xsl:for-each select="msxsl:node-set($sortedcopy)/food">
            <xsl:choose>
                <xsl:when test="position() = 1">
                    <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:choose>
                        <xsl:when test="location != preceding-sibling::food[1]/location">
                                        <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                        </xsl:when>
                    </xsl:choose>
                </xsl:otherwise>
            </xsl:choose>
            <tr>
                <xsl:if test="position() mod 2 != 1">
                    <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                </xsl:if>
                <td width="80%" valign="top">
                    <xsl:value-of select="name" />
                </td>
                <td width="10%" style="text-align:center;" valign="top">
                    <xsl:choose>
                        <xsl:when test="children/food != ''"> </xsl:when>
                        <xsl:otherwise><xsl:value-of select="qty" /></xsl:otherwise>
                    </xsl:choose>
                </td>
            </tr>
            <xsl:if test="children/food">
                <tr>
                    <xsl:if test="position() mod 2 != 1">
                        <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                    </xsl:if>
                    <td colspan="3" class="indentfood">
                        <xsl:call-template name="foodplugin">
                            <xsl:with-param name="food" select="." />
                        </xsl:call-template>
                    </td>
                </tr>
            </xsl:if>
          </xsl:for-each>
    </body>
    </html>
</xsl:template>

Desired

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
        Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
            BC
            California
        Golden
        Macintosh

Result

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
    Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
        BC
    California
    Golden
    Macintosh
Share Improve this question edited Nov 19, 2024 at 22:07 n00b asked Nov 19, 2024 at 5:03 n00bn00b 11 bronze badge 5
  • 1. Please post an executable XSLT, not snippets taken out of context. 2. If (as it seems) you want an HTML result, consider using a list. – michael.hor257k Commented Nov 19, 2024 at 5:19
  • Side question: why are you adding U+160, the non-breaking space, rather than normal spaces? Any are you using both <br /> and XSL text? What is this result supposed to be? Is it HTML? Is it text? – Mike 'Pomax' Kamermans Commented Nov 19, 2024 at 5:19
  • @Mike'Pomax'Kamermans Because a browser would ignore them? – michael.hor257k Commented Nov 19, 2024 at 5:20
  • @michael.hor257k depends entirely on CSS? And if this is supposed to become HTML output, then relying on indentation at all would be really weird given that HTML already comes with two indented (by default, but trivially overruled by CSS) list flavours to choose from. – Mike 'Pomax' Kamermans Commented Nov 19, 2024 at 5:21
  • @n00b Also please fix your XML example to be a well-formed XML document. – michael.hor257k Commented Nov 19, 2024 at 5:41
Add a comment  | 

2 Answers 2

Reset to default 0

Here is a simple stylesheet that uses XSLT's recursive processing model to produce a nested HTML unordered list:

XSLT 1.0

<xsl:stylesheet version="1.0"   
xmlns:xsl="http://www.w3./1999/XSL/Transform">    
<xsl:output method="html" />

<xsl:template match="/ | children">    
    <ul> 
        <xsl:apply-templates select="food"/>
    </ul>
</xsl:template>    

<xsl:template match="food">    
    <li>
        <xsl:value-of select="name"/>
        <xsl:apply-templates select="children"/>
    </li>
</xsl:template>

</xsl:stylesheet>

Given a well-formed (!!!) XML input:

<food>
    <name>Junk Food</name>
    <qty>1</qty>
    <children>
        <food>
            <name>Gummies</name>
            <qty>7</qty>
            <children>
                <food>
                    <name>Chocolate</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Sour</name>
                    <qty>2</qty>
                    <children />
                </food>
            </children>
        </food>
        <food>
            <name>Chips</name>
            <qty>8</qty>
            <children>
                <food>
                    <name>Salt &amp; Vinegar</name>
                    <qty>5</qty>
                </food>
                <food>
                    <name>Lightly Salted</name>
                    <qty>1</qty>
                    <children>
                        <food>
                            <name>Rippled</name>
                            <qty>2</qty>
                            <children/>
                        </food>
                    </children>
                </food>
            </children>
        </food>
        <food>
            <name>Fruit</name>
            <qty>18</qty>
            <children>
                <food>
                    <name>Pineapple</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Apple</name>
                    <qty>13</qty>
                    <children>
                        <food>
                            <name>Macintosh</name>
                            <qty>8</qty>
                            <children/>
                        </food>
                        <food>
                            <name>Golden</name>
                            <qty>2</qty>
                            <children/>
                        </food>
                        <food>
                            <name>Granny Smith</name>
                            <qty>3</qty>
                            <children/>
                        </food>
                    </children>
                </food>
            </children>
        </food>
    </children>
</food>

the (rendered) result will be:

You can add CSS code to further style the result.

Here is an even simpler stylesheet that produces a text result indented by tab characters. This also uses XSLT's native recursion to increase the indent at each level.

XSLT 1.0

<xsl:stylesheet version="1.0"   
xmlns:xsl="http://www.w3./1999/XSL/Transform">    
<xsl:output method="text" />

<xsl:template match="food">  
    <xsl:param name="indent"/>  
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="name"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates select="children/food">
        <xsl:with-param name="indent" select="concat($indent, '&#9;')"/>
    </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

Using the same XML example input as in my previous answer, the result here will be:

Junk Food
    Gummies
        Chocolate
        Sour
    Chips
        Salt & Vinegar
        Lightly Salted
            Rippled
    Fruit
        Pineapple
        Apple
            Macintosh
            Golden
            Granny Smith

It has been awhile since I coded, and a friend has asked me for help. I can't seem to get my head around it. It's old code I'm trying to fix up.

Basically, I'm trying to make a table that indents for each child of the parent.

I can get it to indent the first child correctly, then it stops. Can someone kindly point in the direction of where I can read up on this?

*Update

I have added code as best as I can atm. Adding during break at work. Will update more if needed after work.

Data - Values have been changes because I've been feeling snackish.

<foods>
    <name>Junk Food</name>
    <qty>1</qty>
    <children>
        <food>
            <name>Gummies</name>
            <qty>7</qty>
            <children>
                <food>
                    <name>Chocolate</name>
                    <qty>5</qty>
                    <children />
                </food>
            </children>
            <children>
                <food>
                    <name>Sour</name>
                    <qty>2</qty>
                    <children />
                </food>
            </children>
        <food>
            <name>Chips</name>
            <qty>8</qty>
            <children>
                <food>
                    <name>Salt & Vinegar</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Lightly Salted</name>
                    <qty>1</qty>
                    <children>
                        <food>
                            <name>Rippled</name>
                            <qty>2</qty>
                            <children>
                        </food>
                    </children>
                </food>
            <children />
        </food>
        <food>
            <name>Fruit</name>
            <qty>18</qty>
            <children>
                <food>
                    <name>Pineapple</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Apple</name>
                    <qty>13</qty>
                    <children>
                        <food>
                        <name>Macintosh</name>
                        <qty>8</qty>
                        <children />
                        </food>
                        <food>
                        <name>Golden</name>
                        <qty>2</qty>
                        <children />
                        </food>
                        <food>
                        <name>Granny Smith</name>
                        <qty>3</qty>
                        <children />
                        </food>
                    </children>
                </food>
            </children>
        </food>
    </children>
</foods>

**Code **

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Character sheet based on the Shadowrun 4th Edition Character Sheet -->
<!-- Created by Keith Rudolph, [email protected] -->
<!-- Version -892 -->
<xsl:stylesheet version="1.0" xmlns:xsl="; xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:include href="ConditionMonitor.xslt"/>
    <xsl:template match="/characters/character">
        <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ".dtd">]]></xsl:text>
        <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
                <title><xsl:value-of select="name" /></title>
                <style type="text/css">
                    *
                    {
                        font-family: segoe condensed, tahoma, trebuchet ms, arial;
                        font-size: 8pt;
                        text-align: left;
                    }
                    .tableborder
                    {
                        border: solid 2px #1c4a2d;
                    }
                    .indent
                    {
                        padding-left: 20px;
                    }
                </style>
            </head>
            <body>

<div class="block" id="foodBlock">
    <table width="100%" cellspacing="0" cellpadding="0" border="0">
        <tr><td width="70%" class="tableborder" style="text-align:center;" valign="top">

                            <table width="100%" cellspacing="0" cellpadding="0" border="0">
                                <tr>
                                    <td width="55%">
                                        <strong>NAME</strong>
                                    </td>
                                    <td width="15%" style="text-align:center;">
                                        <strong>QTY.</strong>
                                    </td>
                                </tr>
                                <xsl:call-template name="food1" />
                            </table>
                        </td>
                    </tr>
                </table>
            </div>


<xsl:template name="foodplugin">
    <xsl:param name="food" />
    <xsl:for-each select="children/food">
        <xsl:sort select="name" />
        <xsl:sort select="foodname" />
        <xsl:value-of select="qty" /><xsl:text>x </xsl:text>
        <xsl:value-of select="name" />
        <xsl:if test="children/food">
            <br /><xsl:text>&#160;&#160;</xsl:text>
            <xsl:call-template name="foodplugin">
                <xsl:with-param name="food" select="." />
            </xsl:call-template>
        </xsl:if>
        <xsl:if test="position() != last()"><br /></xsl:if>
    </xsl:for-each>
</xsl:template>

<xsl:template name="food1">
        <xsl:variable name="halfcut" select="count(foods/food)"/>
        <xsl:variable name="sortedcopy">
            <xsl:for-each select="foods/food">
                <xsl:sort select="food" />
                <xsl:sort select="name" />
                <xsl:if test="position() &lt;= $halfcut">
                    <xsl:copy-of select="current()"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
        <xsl:for-each select="msxsl:node-set($sortedcopy)/food">
            <xsl:choose>
                <xsl:when test="position() = 1">
                    <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:choose>
                        <xsl:when test="location != preceding-sibling::food[1]/location">
                                        <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                        </xsl:when>
                    </xsl:choose>
                </xsl:otherwise>
            </xsl:choose>
            <tr>
                <xsl:if test="position() mod 2 != 1">
                    <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                </xsl:if>
                <td width="80%" valign="top">
                    <xsl:value-of select="name" />
                </td>
                <td width="10%" style="text-align:center;" valign="top">
                    <xsl:choose>
                        <xsl:when test="children/food != ''"> </xsl:when>
                        <xsl:otherwise><xsl:value-of select="qty" /></xsl:otherwise>
                    </xsl:choose>
                </td>
            </tr>
            <xsl:if test="children/food">
                <tr>
                    <xsl:if test="position() mod 2 != 1">
                        <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                    </xsl:if>
                    <td colspan="3" class="indentfood">
                        <xsl:call-template name="foodplugin">
                            <xsl:with-param name="food" select="." />
                        </xsl:call-template>
                    </td>
                </tr>
            </xsl:if>
          </xsl:for-each>
    </body>
    </html>
</xsl:template>

Desired

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
        Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
            BC
            California
        Golden
        Macintosh

Result

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
    Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
        BC
    California
    Golden
    Macintosh

It has been awhile since I coded, and a friend has asked me for help. I can't seem to get my head around it. It's old code I'm trying to fix up.

Basically, I'm trying to make a table that indents for each child of the parent.

I can get it to indent the first child correctly, then it stops. Can someone kindly point in the direction of where I can read up on this?

*Update

I have added code as best as I can atm. Adding during break at work. Will update more if needed after work.

Data - Values have been changes because I've been feeling snackish.

<foods>
    <name>Junk Food</name>
    <qty>1</qty>
    <children>
        <food>
            <name>Gummies</name>
            <qty>7</qty>
            <children>
                <food>
                    <name>Chocolate</name>
                    <qty>5</qty>
                    <children />
                </food>
            </children>
            <children>
                <food>
                    <name>Sour</name>
                    <qty>2</qty>
                    <children />
                </food>
            </children>
        <food>
            <name>Chips</name>
            <qty>8</qty>
            <children>
                <food>
                    <name>Salt & Vinegar</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Lightly Salted</name>
                    <qty>1</qty>
                    <children>
                        <food>
                            <name>Rippled</name>
                            <qty>2</qty>
                            <children>
                        </food>
                    </children>
                </food>
            <children />
        </food>
        <food>
            <name>Fruit</name>
            <qty>18</qty>
            <children>
                <food>
                    <name>Pineapple</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Apple</name>
                    <qty>13</qty>
                    <children>
                        <food>
                        <name>Macintosh</name>
                        <qty>8</qty>
                        <children />
                        </food>
                        <food>
                        <name>Golden</name>
                        <qty>2</qty>
                        <children />
                        </food>
                        <food>
                        <name>Granny Smith</name>
                        <qty>3</qty>
                        <children />
                        </food>
                    </children>
                </food>
            </children>
        </food>
    </children>
</foods>

**Code **

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Character sheet based on the Shadowrun 4th Edition Character Sheet -->
<!-- Created by Keith Rudolph, [email protected] -->
<!-- Version -892 -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3./1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:include href="ConditionMonitor.xslt"/>
    <xsl:template match="/characters/character">
        <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3./TR/xhtml1/DTD/xhtml1-strict.dtd">]]></xsl:text>
        <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
                <title><xsl:value-of select="name" /></title>
                <style type="text/css">
                    *
                    {
                        font-family: segoe condensed, tahoma, trebuchet ms, arial;
                        font-size: 8pt;
                        text-align: left;
                    }
                    .tableborder
                    {
                        border: solid 2px #1c4a2d;
                    }
                    .indent
                    {
                        padding-left: 20px;
                    }
                </style>
            </head>
            <body>

<div class="block" id="foodBlock">
    <table width="100%" cellspacing="0" cellpadding="0" border="0">
        <tr><td width="70%" class="tableborder" style="text-align:center;" valign="top">

                            <table width="100%" cellspacing="0" cellpadding="0" border="0">
                                <tr>
                                    <td width="55%">
                                        <strong>NAME</strong>
                                    </td>
                                    <td width="15%" style="text-align:center;">
                                        <strong>QTY.</strong>
                                    </td>
                                </tr>
                                <xsl:call-template name="food1" />
                            </table>
                        </td>
                    </tr>
                </table>
            </div>


<xsl:template name="foodplugin">
    <xsl:param name="food" />
    <xsl:for-each select="children/food">
        <xsl:sort select="name" />
        <xsl:sort select="foodname" />
        <xsl:value-of select="qty" /><xsl:text>x </xsl:text>
        <xsl:value-of select="name" />
        <xsl:if test="children/food">
            <br /><xsl:text>&#160;&#160;</xsl:text>
            <xsl:call-template name="foodplugin">
                <xsl:with-param name="food" select="." />
            </xsl:call-template>
        </xsl:if>
        <xsl:if test="position() != last()"><br /></xsl:if>
    </xsl:for-each>
</xsl:template>

<xsl:template name="food1">
        <xsl:variable name="halfcut" select="count(foods/food)"/>
        <xsl:variable name="sortedcopy">
            <xsl:for-each select="foods/food">
                <xsl:sort select="food" />
                <xsl:sort select="name" />
                <xsl:if test="position() &lt;= $halfcut">
                    <xsl:copy-of select="current()"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
        <xsl:for-each select="msxsl:node-set($sortedcopy)/food">
            <xsl:choose>
                <xsl:when test="position() = 1">
                    <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:choose>
                        <xsl:when test="location != preceding-sibling::food[1]/location">
                                        <tr><td colspan="3" style="border-bottom:solid black 1px;"><strong><xsl:value-of select="location" /></strong></td></tr>
                        </xsl:when>
                    </xsl:choose>
                </xsl:otherwise>
            </xsl:choose>
            <tr>
                <xsl:if test="position() mod 2 != 1">
                    <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                </xsl:if>
                <td width="80%" valign="top">
                    <xsl:value-of select="name" />
                </td>
                <td width="10%" style="text-align:center;" valign="top">
                    <xsl:choose>
                        <xsl:when test="children/food != ''"> </xsl:when>
                        <xsl:otherwise><xsl:value-of select="qty" /></xsl:otherwise>
                    </xsl:choose>
                </td>
            </tr>
            <xsl:if test="children/food">
                <tr>
                    <xsl:if test="position() mod 2 != 1">
                        <xsl:attribute name="bgcolor">#e4e4e4</xsl:attribute>
                    </xsl:if>
                    <td colspan="3" class="indentfood">
                        <xsl:call-template name="foodplugin">
                            <xsl:with-param name="food" select="." />
                        </xsl:call-template>
                    </td>
                </tr>
            </xsl:if>
          </xsl:for-each>
    </body>
    </html>
</xsl:template>

Desired

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
        Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
            BC
            California
        Golden
        Macintosh

Result

Gummies
    Chocolate
    Sour
Chips
    Salt & Vinegar
    Lightly Salted
    Rippled
Fruit
    Pineapple
    Apple
        Granny Smith
        BC
    California
    Golden
    Macintosh
Share Improve this question edited Nov 19, 2024 at 22:07 n00b asked Nov 19, 2024 at 5:03 n00bn00b 11 bronze badge 5
  • 1. Please post an executable XSLT, not snippets taken out of context. 2. If (as it seems) you want an HTML result, consider using a list. – michael.hor257k Commented Nov 19, 2024 at 5:19
  • Side question: why are you adding U+160, the non-breaking space, rather than normal spaces? Any are you using both <br /> and XSL text? What is this result supposed to be? Is it HTML? Is it text? – Mike 'Pomax' Kamermans Commented Nov 19, 2024 at 5:19
  • @Mike'Pomax'Kamermans Because a browser would ignore them? – michael.hor257k Commented Nov 19, 2024 at 5:20
  • @michael.hor257k depends entirely on CSS? And if this is supposed to become HTML output, then relying on indentation at all would be really weird given that HTML already comes with two indented (by default, but trivially overruled by CSS) list flavours to choose from. – Mike 'Pomax' Kamermans Commented Nov 19, 2024 at 5:21
  • @n00b Also please fix your XML example to be a well-formed XML document. – michael.hor257k Commented Nov 19, 2024 at 5:41
Add a comment  | 

2 Answers 2

Reset to default 0

Here is a simple stylesheet that uses XSLT's recursive processing model to produce a nested HTML unordered list:

XSLT 1.0

<xsl:stylesheet version="1.0"   
xmlns:xsl="http://www.w3./1999/XSL/Transform">    
<xsl:output method="html" />

<xsl:template match="/ | children">    
    <ul> 
        <xsl:apply-templates select="food"/>
    </ul>
</xsl:template>    

<xsl:template match="food">    
    <li>
        <xsl:value-of select="name"/>
        <xsl:apply-templates select="children"/>
    </li>
</xsl:template>

</xsl:stylesheet>

Given a well-formed (!!!) XML input:

<food>
    <name>Junk Food</name>
    <qty>1</qty>
    <children>
        <food>
            <name>Gummies</name>
            <qty>7</qty>
            <children>
                <food>
                    <name>Chocolate</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Sour</name>
                    <qty>2</qty>
                    <children />
                </food>
            </children>
        </food>
        <food>
            <name>Chips</name>
            <qty>8</qty>
            <children>
                <food>
                    <name>Salt &amp; Vinegar</name>
                    <qty>5</qty>
                </food>
                <food>
                    <name>Lightly Salted</name>
                    <qty>1</qty>
                    <children>
                        <food>
                            <name>Rippled</name>
                            <qty>2</qty>
                            <children/>
                        </food>
                    </children>
                </food>
            </children>
        </food>
        <food>
            <name>Fruit</name>
            <qty>18</qty>
            <children>
                <food>
                    <name>Pineapple</name>
                    <qty>5</qty>
                    <children />
                </food>
                <food>
                    <name>Apple</name>
                    <qty>13</qty>
                    <children>
                        <food>
                            <name>Macintosh</name>
                            <qty>8</qty>
                            <children/>
                        </food>
                        <food>
                            <name>Golden</name>
                            <qty>2</qty>
                            <children/>
                        </food>
                        <food>
                            <name>Granny Smith</name>
                            <qty>3</qty>
                            <children/>
                        </food>
                    </children>
                </food>
            </children>
        </food>
    </children>
</food>

the (rendered) result will be:

You can add CSS code to further style the result.

Here is an even simpler stylesheet that produces a text result indented by tab characters. This also uses XSLT's native recursion to increase the indent at each level.

XSLT 1.0

<xsl:stylesheet version="1.0"   
xmlns:xsl="http://www.w3./1999/XSL/Transform">    
<xsl:output method="text" />

<xsl:template match="food">  
    <xsl:param name="indent"/>  
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="name"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates select="children/food">
        <xsl:with-param name="indent" select="concat($indent, '&#9;')"/>
    </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

Using the same XML example input as in my previous answer, the result here will be:

Junk Food
    Gummies
        Chocolate
        Sour
    Chips
        Salt & Vinegar
        Lightly Salted
            Rippled
    Fruit
        Pineapple
        Apple
            Macintosh
            Golden
            Granny Smith

本文标签: xslt 10XSL Indenting resultsStack Overflow