I have an XML document I need to generate to integrate with a 3rd party vendor. Their paradigm is that any string elements are set as attributes, while any complex objects are separate nodes with the same rule.
I'm trying to use XSLT to convert our serialized representation of this object into their document format based on their .dtd. Unfortunately, I can't decorate these particular elements with [XmlAttribute] because their value could be null (I'm using XSLT to remove these nodes before sending the request).
Basically, I'm trying to figure out in XSLT how to do the following: "For each child of my element, if that child has no children, convert that element to a property on my element."
I'm working with the following snippet I've found that appears to do what I need:
<!-- Match elements that are parents -->
<xsl:template match="*[*]">
<xsl:choose>
<!-- Only convert children if this element has no attributes -->
<!-- of its own -->
<xsl:when test="not(@*)">
<xsl:copy>
<!-- Convert children to attributes if the child has -->
<!-- no children or attributes and has a unique name -->
<!-- amoung its siblings -->
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="not(*) and not(@*) and
not(preceding-sibling::*[name( ) =
name(current( ))])
and
not(following-sibling::*[name( ) =
name(current( ))])">
<xsl:attribute name="{local-name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
However, this errors with:
Exception::System.Xml.Xsl.XslTransformException: Attribute and namespace nodes cannot be added to the parent element after a text, comment, pi, or sub-element node has already been added.
My XSLT skills are a bit weak. Any help would be appreciated!
For more info, say the doc looks like this:
<Root>
<type>Foo</type>
<includeHTML>Yes</includeHTML>
<SubRoot>
<SubSubRoot>
<ID>2.4</ID>
</SubSubRoot>
</SubRoot>
</Root>
I want the result to look like this:
<Root type="foo" includeHTML="Yes">
<SubRoot>
<SubSubRoot ID="2.4" />
</SubRoot>
</Root>
EDIT EDIT: I'm using .NET 4.5.1, XSLT 1.0 only. Doh!