TechPreview
TechPreview

Reputation: 1

XSLT - Show only if child contains specific text

I am very new to XSLT. Unable to figure out , how to show a particular row only if the child nodes contain one of the specific texts.

In my case we have a list of call logs. The phone number can be of multiple type, but i want show them in table only when the phone number type is either voice or sms.

Current Output Screenshot

My XML

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="example.xsl"?>
<CallLogs>
    <cInfoBj>
        <phNoBJ>
            <phNo>123</phNo>
            <phTypeBj>
                <phTypeName>VOICE</phTypeName>
            </phTypeBj>
        </phNoBJ>
    </cInfoBj>
    <cInfoBj>
        <phNoBJ>
            <phNo>456</phNo>
            <phTypeBj>
                <phTypeName>VOICE</phTypeName>
            </phTypeBj>
            <phTypeBj>
                <phTypeName>SMS</phTypeName>
            </phTypeBj>
        </phNoBJ>
    </cInfoBj>
    <cInfoBj>
        <phNoBJ>
            <phNo>789</phNo>
            <phTypeBj>
                <phTypeName>SMS</phTypeName>
            </phTypeBj>
        </phNoBJ>
    </cInfoBj>
     <cInfoBj>
        <phNoBJ>
            <phNo>890</phNo>
            <phTypeBj>
                <phTypeName>FAX</phTypeName>
            </phTypeBj>
        </phNoBJ>
    </cInfoBj>
</CallLogs>

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Phone Number</th>
        <th>Type</th>
      </tr>
      
      <xsl:for-each select="/CallLogs/cInfoBj/phNoBJ">
        <tr>
            <td><xsl:value-of select="phNo"/></td>
            <td>
                <xsl:for-each select="phTypeBj">
                    <div><xsl:value-of select="phTypeName"/></div>
                </xsl:for-each>
            </td>
        </tr>
      </xsl:for-each>
      
    </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 439

Answers (2)

Michael Kay
Michael Kay

Reputation: 163322

Change the xsl:for-each to xsl:apply-templates, and define template rules for the different things it can select:

<xsl:apply-templates select="/CallLogs/cInfoBj/phNoBJ"/>

then

<xsl:template match="phNoBJ[.//phTypeName=('VOICE', 'SMS')]">
        <tr>
            <td><xsl:value-of select="phNo"/></td>
            <td>
                <xsl:for-each select="phTypeBj">
                    <div><xsl:value-of select="phTypeName"/></div>
                </xsl:for-each>
            </td>
        </tr>
</xsl:template>

<xsl:template match="phNoBJ"/> <!-drop element if it doesn't match the conditions-->

Template rules are the idiomatic way of structuring XSLT code; if you're a beginner, then every time you find yourself writing xsl:for-each, consider using xsl:apply-templates instead.

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 116993

Change:

<xsl:for-each select="/CallLogs/cInfoBj/phNoBJ">

to:

<xsl:for-each select="/CallLogs/cInfoBj/phNoBJ[phTypeBj/phTypeName='VOICE' or phTypeBj/phTypeName='SMS']">

You may need to add a similar predicate to your other xsl:for-each instruction if you don't want to list the additional types for numbers with multiple types.

Upvotes: 0

Related Questions