XSLT 2.0 Testing element names that start with a certain value

Go To StackoverFlow.com

2

I've done some looking around, but I'm not seeing an obvious answer to my problem. I'm sure I'm overlooking something, but I don't know what.

I've done some preprocessing on the XML below to edit some of the element names, and after preprocessing I have an XSL stylesheet that does a simple identity transform. However, I'm wondering if there's a way to avoid the preprocessing step and accomplish everything in one stylesheet. The primary difference between the two XML inputs are <subj*> has become <subj>.

Is there a method for testing an element name for a starting (or ending, too, I suppose) value? Thanks very much for your time & suggestions.

I have XML input that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <row>
      <issueNumber>1.001</issueNumber>
      <subj1>Cats</subj1>
      <subj2>LOLCats</subj2>
      <subj3>Cheezburgers</subj3>
      <subj4></subj4>
   </row>
   <row>
      <issueNumber>2.001</issueNumber>
      <subj1>Cats</subj1>
      <subj2>LOLCats</subj2>
      <subj3>NOMS</subj3>
      <subj4>Cheezburger</subj4>
   </row>
   <row>
      <issueNumber>3.001</issueNumber>
      <subj1>NOMS</subj1>
      <subj2></subj2>
      <subj3></subj3>
      <subj4></subj4>
   </row>
</root>

I'm processing it with the following XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="row">
    <!--<xsl:result-document href="{concat(issueNumber, '.xml')}">-->
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    <!--</xsl:result-document>-->    
</xsl:template>

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

<xsl:template match="subj">
    <xsl:choose>
        <xsl:when test="not(string(.))"></xsl:when>
        <xsl:when test="string(.)">
            <subject>
                <xsl:apply-templates />
            </subject>
        </xsl:when>
    </xsl:choose>
</xsl:template>

2012-04-04 17:37
by CanOfBees


1

If I understand the question correctly, you could do something like this:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[starts-with(name(),'subj')]">
    <subj>
      <xsl:if test="string(.)">
        <subject>
          <xsl:apply-templates/>
        </subject>
      </xsl:if>
    </subj>
  </xsl:template>

</xsl:stylesheet>

Using your XML input (corrected to be well-formed):

<root>
  <row>
    <issueNumber>1.001</issueNumber>
    <subj1>Cats</subj1>
    <subj2>LOLCats</subj2>
    <subj3>Cheezburgers</subj3>
    <subj4></subj4>
  </row>
  <row>
    <issueNumber>2.001</issueNumber>
    <subj1>Cats</subj1>
    <subj2>LOLCats</subj2>
    <subj3>NOMS</subj3>
    <subj4>Cheezburger</subj4>
  </row>
  <row>
    <issueNumber>3.001</issueNumber>
    <subj1>NOMS</subj1>
    <subj2></subj2>
    <subj3></subj3>
    <subj4></subj4>
  </row>
</root>

Produces the following output:

<root>
   <row>
      <issueNumber>1.001</issueNumber>
      <subj>
         <subject>Cats</subject>
      </subj>
      <subj>
         <subject>LOLCats</subject>
      </subj>
      <subj>
         <subject>Cheezburgers</subject>
      </subj>
      <subj/>
   </row>
   <row>
      <issueNumber>2.001</issueNumber>
      <subj>
         <subject>Cats</subject>
      </subj>
      <subj>
         <subject>LOLCats</subject>
      </subj>
      <subj>
         <subject>NOMS</subject>
      </subj>
      <subj>
         <subject>Cheezburger</subject>
      </subj>
   </row>
   <row>
      <issueNumber>3.001</issueNumber>
      <subj>
         <subject>NOMS</subject>
      </subj>
      <subj/>
      <subj/>
      <subj/>
   </row>
</root>
2012-04-04 17:56
by Daniel Haley
I've edited the XML input - hadn't spaced </root> over far enough - sorry about that. your stylesheet is closest with the succinct usage of xsl:template match="*[starts-with...]". thanks, very much, for the help - CanOfBees 2012-04-04 20:11
@CanOfBees - You're very welcome - Daniel Haley 2012-04-05 01:28


2

Are you searching for something like "regex" in XSLT? If you are, this link might be very useful for you: http://www.w3.org/TR/xslt20/#regular-expressions

However, this solution only works in XSLT 2.0. You might lose compatibility to older XSLT versions.

2012-04-04 17:41
by Dominik M.
thanks, Dominik! the problem wasn't regex, but rather correct usage of starts-with() in xsl:template match="..." - CanOfBees 2012-04-04 20:05
also - thanks for the link to the spec -- it's a good reminder of what's available - CanOfBees 2012-04-04 20:12
Year, specifications often are the best reference - Dominik M. 2012-04-05 15:21
Ads