0

Let's say I have the following XML input:

<?xml version="1.0"?>
<root>
  <urls>
    <url>http://foo</url>
    <url>http://bar</url>
  </urls>
  <resources lang="en-US">
    <resourceString id='url-fmt'>See URL: {0}</resourceString>
  </resources>
</root>

I would like to produce the following output with XSL (can use 1.0, 2.0 or even 3.0):

<?xml version="1.0"?>
<body>
  <p>See URL: <a href="http://foo">http://foo</a></p>
  <p>See URL: <a href="http://bar">http://bar</a></p>
</body>

I have the following XSL stylesheet stub, but I struggle to find the appropriate function which will tokenize the resource string, extract {0} and replace it with a node. replace() seems to be of no help since it operates only with strings:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
  <xsl:variable name="urlResString"
                select="/root/resources/resourceString[@id='url-fmt']" />
  <xsl:template match="/">
    <body>
      <xsl:apply-templates select="/root/urls/url" />
    </body>
  </xsl:template>
  <xsl:template match="url">
    <p>
      <xsl:variable name='linkToInsert'>
        <a href='{.}'><xsl:value-of select='.'/></a>
      </xsl:variable>
      <xsl:value-of
           select="replace($urlResString, '\{0}', $linkToInsert)" />
    </p>
  </xsl:template>
</xsl:stylesheet>

What is generated here is:

<?xml version="1.0"?>
<body>
  <p>See URL: http://foo</p>
  <p>See URL: http://bar</p>
</body>

If you can guide me to the correct functions to use, that would be great.

Note: I may have to do this on strings with both {0}, {1}, etc. a bit like the format-string functions in .NET.

Thanks!

2 Answers 2

2

you can use xsl:analyze-string as follows:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:variable name="urlResString"
        select="/root/resources/resourceString[@id='url-fmt']" />
    <xsl:template match="/">
        <body>
            <xsl:apply-templates select="/root/urls/url" />
        </body>
    </xsl:template>
    <xsl:template match="url">
        <p>
            <xsl:variable name='linkToInsert'>
                <a href='{.}'><xsl:value-of select='.'/></a>
            </xsl:variable>
            <xsl:analyze-string select="$urlResString" regex="\{{\d\}}">
                <xsl:matching-substring>
                    <xsl:copy-of select="$linkToInsert"/>
                </xsl:matching-substring>
                <xsl:non-matching-substring>
                    <xsl:copy/>
                </xsl:non-matching-substring>
            </xsl:analyze-string>
        </p>
    </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

Comments

1
 <xsl:template match="root/urls">
        <body>
        <xsl:for-each select="url">
            <p>
                <xsl:value-of select=" substring-before(parent::urls/following-sibling::resources/resourceString,' {')"/><xsl:text> </xsl:text>
                <a href="{.}"><xsl:value-of select="."/></a>
            </p>
        </xsl:for-each>
        </body>
    </xsl:template>
    <xsl:template match="resources"/>
Try it

1 Comment

thank you, that would do it in this case, but the solution from Joel is more elegant and will fit better with other localizations, where the {0} string can be in the middle of the string, and can be extended to support multiple placeholders in the string more easily

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.