3

I have elements:

<A>11511/direction=sink</A>
<B>110/direction=src</B>

Of course there are some elements without /direction suffix that is importnat to mention.

If elements A and B contain string /direction... I want to have the value before string /direction. If elements do not contain /direction then take regular value as usual. What should I add in value-of clause ?

<newElementA><xsl:value-of select="A"/></newElementA>
<newElementB><xsl:value-of select="B"/></newElementB>

I tried with <xsl:value-of select="substring-before(A,'/')"/> but then values which do not have value /direction are set with value null which is not correct

I also tried this but then getting error:

     <newelementA><xsl:value-of select="if (contains(A,'/')) 
then substring-before(A,'/') else A"/></newelementA>

I want to have values 11511and110 in result.

Thanks

3
  • Possible duplicate of xslt: substring-before Commented Dec 18, 2016 at 15:39
  • It is not a duplicate of this question because if I put <xsl:value-of select="substring-before(A,'/')"/> I am getting null values for those elements which do not contain /direction in the value.., Can you please help me? Commented Dec 18, 2016 at 16:17
  • Are you limited to XSLT 1.0? If you can use XSLT 2.0 or above, you have access to regex functions that are more flexible than the older substring functions. Please clarify which version of XSLT you can use. Commented Dec 18, 2016 at 22:00

2 Answers 2

2

One possibility is to use conditional processing, and choose between alternative actions depending on the content.

For example, this input (only using A for simplicity):

<root>
  <A>11511/direction=sink</A>
  <A>test</A>
</root>

with this stylesheet:

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

  <xsl:template match="root">
    <newRoot>
      <xsl:apply-templates select="*"/>
    </newRoot>
  </xsl:template>

  <!-- Create newElementA -->
  <xsl:template match="A">
    <newElementA>
      <xsl:call-template name="chooseContent"/>
    </newElementA>
  </xsl:template>

  <!-- Reusable template to determine element content -->
  <xsl:template name="chooseContent">
    <xsl:choose>
      <xsl:when test="contains(.,'/direction')">
        <xsl:value-of select="substring-before(.,'/direction')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Ignore unknown elements -->
  <xsl:template match="*"/>
</xsl:stylesheet>

results in:

<newRoot>
  <newElementA>11511</newElementA>
  <newElementA>test</newElementA>
</newRoot>
Sign up to request clarification or add additional context in comments.

Comments

1

If you can use XSLT 2.0 or newer, the regular-expression function replace gives you the flexibility you need.

Example:

<xsl:value-of select="replace(., '(.*?)/.*$', '$1')"/>

I've confirmed that this produces the output you say you want for any string 1235sdfa/sdff93rjdf, and also for any string asda98273jasdf that does not contain a /.

3 Comments

Ah yes, it could be so simple. Hopefully, XSLT 2.0 will be more widely supported in the near future.
@Meyer -- If you're using the Microsoft XML libraries, don't expect XSLT 2.0 any time soon.
Oh well. I'm mostly bound to Linux with libxml2, where XSLT 2.0 seems equally unlikely. Hence my answer for good old portable 1.0.

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.