How can I get self-closing tags in the output XML by using XslCompiledTransform?

2.1k Views Asked by At

Please help me...

I have input XML document:

<?xml version="1.0" encoding="utf-8"?>
<Root>
    <Object>
      <GUID>201110180954525010129</GUID>
      <Meta name="FILENAME" format="string" frate="" />
    </Object>
</Root>

I need to transform it into the next xml:

<?xml version="1.0" encoding="UTF-8"?>
<Root> 
    <Object> 
        <GUID>201110180954525010129</GUID>
        <FILENAME/> 
    </Object>
<Root>

I've created the next style sheet:

<?xml version="1.0" encoding="utf-8"?>
<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:template match="/">
<xsl:element name="Root">

<xsl:for-each select="Root/Object">
<xsl:element name="Object">

<xsl:element name="FILENAME">
        <xsl:value-of select="Meta[@name='FILENAME']" />
</xsl:element>

<xsl:element name="GUID">
        <xsl:value-of select="GUID" />
</xsl:element>

</xsl:element>
</xsl:for-each>

</xsl:element>
</xsl:template>
</xsl:stylesheet>

But when I trying to transform it, I get the next result:

<?xml version="1.0" encoding="UTF-8"?>
<Root> 
    <Object> 
    <GUID>201110180954525010129</GUID>
        <FILENAME> </FILENAME> 
    </MAObject>
<Root>

How can I tell to interpret self-closing tags ?

C# transformation code:

        var stylesheet = "styleSheet.xml";
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load("input.xml");
        XslCompiledTransform xslTransform = new XslCompiledTransform();
        xslTransform.Load(styleSheet);

            XmlDocument xmlDocumentOutput = new XmlDocument();
            XmlDeclaration xmlDocumentOutputDeclaration = xmlDocumentOutput.CreateXmlDeclaration("1.0", "utf-8", null);
            xmlDocumentOutput.AppendChild(xmlDocumentOutputDeclaration);

            using (XmlWriter xmlWriter = xmlDocumentOutput.CreateNavigator().AppendChild())
            {
                xslTransform.Transform(xmlDocument.CreateNavigator(), null, xmlWriter);
            }

            return xmlDocumentOutput;
3

There are 3 best solutions below

1
On

I tried our samples with XslCompiledTransform, the output I get is

<Root>
  <Object>
    <FILENAME></FILENAME>
    <GUID>201110180954525010129</GUID>
  </Object>
</Root>

How do you run the transformation exactly, how do you look at the output? With XML an empty "foo" element can be marked up as <foo></foo> or <foo/> or <foo />, these forms are semantically equivalent. Why do you need a particular form? Is the output of the XSLT transformation not processed by an XML parser?

[edit]Try whether replacing

<xsl:element name="FILENAME">
        <xsl:value-of select="Meta[@name='FILENAME']" />
</xsl:element>

with

<FILENAME>
  <xsl:if test="normalize-space(Meta[@name='FILENAME'])">
    <xsl:value-of select="Meta[@name='FILENAME']"/>
  </xsl:if>
</FILENAME>

at least ensures the FILENAME element you get is empty.

0
On

Try removing the linebreaks (and any other whitespace) around <xsl:value-of> in the template that matches FILENAME. They are text nodes that show up in the result.

0
On

I don't know if it will make any difference, but try this stylesheet, which has separate matching templates for the Meta with and without data. If nothing else, it is built on the identity template and so removes the need for hard-coding so many element names in your original XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="Meta">
      <xsl:element name="{@name}" />
   </xsl:template>

   <xsl:template match="Meta[. != '']">
      <xsl:element name="{@name}">
         <xsl:apply-templates select="node()"/>
      </xsl:element>
   </xsl:template>

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

When I test this, I get the following result:

<Root>
   <Object>
      <GUID>201110180954525010129</GUID>
      <FILENAME/>
   </Object>
</Root>