Reputation: 63816
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:
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>
Upvotes: 2
Views: 2709
Reputation: 117165
- 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>
- 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>
Upvotes: 3
Reputation: 86774
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>
Upvotes: 3