2

A legacy XML feed we want to consume (it's coupled to a specific database and has no XSD) emits "Y" or "N" as truth values. We are creating an XSD and auto-generating C# classes from this, with some transforms to make things neater.

So if I have fields like <IsFed>Y</IsFed> on an object, how can I transform these using XSLT so something that would validate against xsd:boolean?

I'm interested in two approaches:

  1. Explicitly listing each field to be transformed
  2. Automatically detecting every such yes/no field (I realise this could have errors)

Sample XML might look like this:

<Animal type="hamster">
 <IsFed>Y</IsFed>
 <Name>Gerald</Name>
</Animal>
<Animal type="cow">
 <IsFed>N</IsFed>
 <Name>acv4445-7</Name>
</Animal>

And it should come out like:

<Animal type="hamster">
 <IsFed>true</IsFed>
 <Name>Gerald</Name>
</Animal>
<Animal type="cow">
 <IsFed>false</IsFed>
 <Name>acv4445-7</Name>
</Animal>
2
  • Seems like a trivial XSL transform since you say you're already doing a transformation. What is the question? Commented Jul 12, 2016 at 16:06
  • @JimGarrison I'm asking how to do the transform since I've never used XLST before. I ask both ways to try and learn a bit more about XSLT. Commented Jul 12, 2016 at 16:27

2 Answers 2

3
  1. Explicitly listing each field to be transformed

XSLT 1.0

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

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

<!-- list every boolean element here -->
<xsl:template match="IsFed | HasShelter | etc.  ">
    <xsl:copy>
        <xsl:value-of select=".='Y'"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

  1. Automatically detecting every such yes/no field (I realise this could have errors)

XSLT 1.0

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

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

<xsl:template match="text()[.='Y']">true</xsl:template>
<xsl:template match="text()[.='N']">false</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

Comments

3

Interesting little problem. Here's one possible solution for XSLT 2 (XSLT 1 solution down below)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[starts-with(name(),'Is') and matches(text(),'[YN]')]/text()">
        <xsl:value-of select="if (.='Y') then 'true' else 'false'"></xsl:value-of>
    </xsl:template>
</xsl:stylesheet>

This is an identity transform plus a template matching the text of any element whose name starts with Is and whose value is Y or N, which it replaces with true or false. It does not affect an element whose name starts with Is whose value is not Y or N.

Here's the same thing for XSLT 1.0

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[substring(name(),1,2) = 'Is' and (text() = 'Y' or text() = 'N')]/text()">
        <xsl:choose> 
            <xsl:when test=". = 'Y'">true</xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Comments

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.