Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8894227
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T23:26:35+00:00 2026-06-14T23:26:35+00:00

I have a stylesheet I’m using with a perl module that only works with

  • 0

I have a stylesheet I’m using with a perl module that only works with XSLT 1.0. I want to create a JSON array inside a JSON dictionary so I need proper comma seperation for the elements. I’m parsing an XHTML table where there are 1 or more spans in the second cell. So for-each select=”./tr” and then for-each select=”./td[1]/span” or something like that.

After changing it a little it behaves as expected as Ian said it would.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD HTML 4.01//EN"  encoding="UTF-8" />
    <xsl:template match="text()">
    </xsl:template>
    <xsl:template match="table/tbody">
        <xsl:text>[</xsl:text>
        <xsl:for-each select="./tr[not(@class='no-results')]">
            <xsl:text>{"</xsl:text>
            <xsl:value-of select="normalize-space(.//strong)" />
            <xsl:text>":{"ingredients":{</xsl:text>
            <xsl:for-each select=".//div[@class='reagent-list']//a[@class='item-link reagent']">
                <xsl:value-of select="substring(./@href, 14)" />:<xsl:value-of select="normalize-space(./span[1])" />
                <xsl:if test="position() != last()">
                    <xsl:text>,</xsl:text>
                </xsl:if>
            </xsl:for-each>
            <xsl:text>}</xsl:text>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>
        <xsl:text>]</xsl:text>
    </xsl:template>
</xsl:stylesheet>

I realize that the stylesheet does not match the xml below. The actual document is huge. I hope you understand what I mean, though. I just made this up:

<table>
  <thead>
    <tr>
      <th>a</th>
      <th>b</th>
      <th>c</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>foo</td>
      <td><span>an element</span></td>
      <td>bar</td>
    </tr>
    <tr>
      <td>foo</td>
      <td><span>an element</span><span>an element</span></td>
      <td>bar</td>
    </tr>
    <tr>
      <td>foo</td>
      <td><span>an element</span><span>an element</span><span>an element</span><span>an element</span></td>
      <td>bar</td>
    </tr>
  </tbody>
</table>

=>

{
  "Row one":["an element"],
  "Row two":["an element", "an element"],
  "Row three":["an element", "an element", "an element", "an element"]
}

Instead I get this:

{
  "Row one":["an element",],
  "Row two":["an element", "an element",],
  "Row three":["an element" "an element" "an element" "an element"]
}

I’ve been using position() and last() in a test tag to print a comma and it seems to work correctly for the outer loop, but how do I tell my test tag to use the inner for-each scope when printing the commas that seperate the array?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T23:26:36+00:00Added an answer on June 14, 2026 at 11:26 pm

    As mentioned by @IanRoberts, it is difficult to give targeted assistance without seeing what your existing XSLT looks like.

    That said, here is a solution that is push-oriented (i.e., no <xsl:for-each>) and does not require last().

    When this XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:my="my"
      exclude-result-prefixes="my"
      version="1.0">
      <xsl:output omit-xml-declaration="no" indent="yes" method="text" />
      <xsl:strip-space elements="*" />
    
      <my:ones>
        <num>one</num>
        <num>two</num>
        <num>three</num>
        <num>four</num>
        <num>five</num>
        <num>six</num>
        <num>seven</num>
        <num>eight</num>
        <num>nine</num>
      </my:ones>
    
      <xsl:template match="/*">
        <xsl:text>{&#10;</xsl:text>
        <xsl:apply-templates select="tbody/tr" />
        <xsl:text>&#10;}</xsl:text>
      </xsl:template>
    
      <xsl:template match="tr">
        <xsl:variable name="vPos" select="position()" />
        <xsl:if test="$vPos &gt; 1">,&#10;</xsl:if>
        <xsl:text>&#09;"Row </xsl:text>
        <xsl:value-of select="document('')/*/my:ones/*[$vPos]" />
        <xsl:text>":[</xsl:text>
        <xsl:apply-templates select="td[2]/span" />
        <xsl:text>]</xsl:text>
      </xsl:template>
    
      <xsl:template match="span">
        <xsl:if test="position() &gt; 1">, </xsl:if>
        <xsl:value-of select="concat('&quot;', ., '&quot;')" />
      </xsl:template>
    
    </xsl:stylesheet>
    

    …is run against the provided XML:

    <table>
      <thead>
        <tr>
          <th>a</th>
          <th>b</th>
          <th>c</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>foo</td>
          <td>
            <span>an element</span></td>
          <td>bar</td>
        </tr>
        <tr>
          <td>foo</td>
          <td>
            <span>an element</span><span>an element</span></td>
          <td>bar</td>
        </tr>
        <tr>
          <td>foo</td>
          <td>
            <span>an element</span><span>an element</span><span>an element</span><span>an element</span></td>
          <td>bar</td>
        </tr>
      </tbody>
    </table>
    

    …the wanted result is produced:

    {
      "Row one":["an element"],
      "Row two":["an element", "an element"],
      "Row three":["an element", "an element", "an element", "an element"]
    }
    

    Explanation:

    • The first template matches the root element. It’s purpose is to apply templates to that element’s <tr> grandchildren and sandwich those results between { and } (adding newlines as appropriate).

    • The second template matches <tr> elements. It outputs row information and is instructed to apply templates to all <span> children of the second <td> element (again, sandwiching the results between braces and other text as necessary).

      • NOTE: instead of using last(), you’ll see that the first element outputs a comma, followed by a newline, if the position of this <tr> in the current context is greater than 1. This has the same effect of applying commas correctly; it’s merely a different way of looking at the same problem (and is what I use because it seems more efficient to me 😉 ).

      • NOTE: to make this solution more extensible, you’ll see that I’m not statically outputting the words "one", "two", etc. in each row. Instead, at the top of the XSLT, I’ve defined a <my:ones> element to hold onto the text values of each “ones” number. When processing each <tr>, I use the position of that <tr> in the current context to retrieve the correct <num> element’s value. I’ve left it as an exercise to the reader, but it would indeed be possible to define <my:tens>, <my:hundreds>, etc. to scale this solution up to potentially large numbers of rows.

    • The final template matches <span> elements. Again, it uses an <xsl:if> element to test whether the position of this <span> in the current context is greater than 1; if so, a comma (followed by a space) is output. After that, we merely concatenate two " symbols with the value of the span sandwiched in-between.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have an XSLT stylesheet that transforms an XML file to JSON format and
I have a stylesheet that makes use of exslt:dynamic module and more precisely, it
I am currently using Apache FOP and have a stylesheet (possibly from RenderX) that
I have a xslt stylesheet with multiple xsl:import s and I want to merge
I have an XSLT stylesheet that processes an XML document to produce HTML. I've
I am using classic ASP. I have a stylesheet that is loaded into RAM
I'm using url routing and I have a stylesheet that is being referenced on
I have an XSL stylesheet that I use to create xHTML fragments. The XML
I have printer stylesheet setup on my site. It works in all browsers but
I have an XSL stylesheet (A) that imports another one (B). A overrides a

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.