We are using XSLT internally to map a single input schema to a large number of distinct output schemas. Most of the servers using these schemas return errors on empty elements, so empty elements cannot appear in the output. In many cases, a piece of data in the input will simply map to a piece of data in the output, possibly with a minor transformation, e.g.:
<!-- Input -->
<ourns:DateCreated>2021-12-09</ourns:DateCreated>
<!-- Output -->
<otherns:CreatedDt>2021-12-09<otherns:CreatedDt>
The XSLT for this is straightforward, even with the "no empty elements" requirement:
<xsl:if test="ourns:DateCreated != ''">
<otherns:CreatedDt>
<xsl:value-of select="ourns:DateCreated/text()"/>
</otherns:CreatedDt>
</xsl:if>
However, when you're mapping thousands of elements across hundreds of schemas, this business of wrapping everything in <xsl:if/> gets tiresome. You could add a function, say:
<xsl:function name="ourfn:createElementIfData">
<xsl:param name="tag" as="xs:string"/>
<xsl:param name="data" as="xs:string"/>
<xsl:if test="$data != ''">
<xsl:element name="{$tag}"><xsl:value-of select="$data"/></xsl:element>
</xsl:if>
</xsl:function>
...
<xsl:sequence select="ourfn:createElementIfData('otherns:CreatedDt', ourns:DateCreated)"/>
But this function will only work if it lives in a stylesheet where both namespaces are declared. If you wanted to share it (as you probably would such a general-purpose function), you would end up needing to either
- Declare every possible
othernsin the shared stylesheet, or - Pass in the fully qualified namespace on every invocation,
both of which feel wrong.
This seems like such a common use case that I feel like there must be a simple way to do it. What am I missing?