Home > Mobile >  Keep empty lines and spaces with xslt
Keep empty lines and spaces with xslt

Time:09-26

I'm trying to transform a xml input adding/removing prefixes but I wanted to keep the xml without other modifications:

This is my method:

bool hc = false;
var usenamespaceprefix = true;
var Content = GetContent("f", "http://www.myschemedefinition.com/form", xmlcontent, usenamespaceprefix, out hc);

string GetContent(string prefix, string urins, string content, bool usenamespaceprefix, out bool hasChanged)
{
    var xslt = String.Empty;

    hasChanged = false;

    var newDocument = new XDocument();
    var result = String.Empty;
    try
    {
        var oldDocument = XDocument.Parse(content);
        switch (usenamespaceprefix)
        {
            case true:
                if (!content.Contains($"xmlns:{prefix}"))
                {
                    xslt = $@"<?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' indent='yes'/>
                                  <xsl:preserve-space elements='*'/>
                                  <xsl:template match='*'>
                                    <xsl:element name='{prefix}:{{name()}}' xmlns:{prefix}='{urins}'>
                                      <xsl:apply-templates select='@* | node()'/>
                                    </xsl:element>
                                  </xsl:template>
                                  <xsl:template match='@*'>
                                    <xsl:attribute name='{{local-name(.)}}'>
                                      <xsl:value-of select='.'/>
                                    </xsl:attribute>
                                  </xsl:template>
                                  <xsl:template match='comment()'>
                                     <xsl:copy />
                                  </xsl:template>
                                </xsl:stylesheet>";

                    using (var stringReader = new StringReader(xslt))
                    {
                        using (XmlReader xsltReader = XmlReader.Create(stringReader))
                        {
                            var transformer = new XslCompiledTransform();
                            transformer.Load(xsltReader);
                            using (XmlReader oldDocumentReader = oldDocument.CreateReader())
                            {
                                using (var newDocumentWriter = newDocument.CreateWriter())
                                {
                                    transformer.Transform(oldDocumentReader, newDocumentWriter);
                                }
                            }
                        }
                    }

                    result = newDocument.ToString();
                }
                else
                {
                    xslt = $@"<?xml version='1.0' encoding='utf-8'?>                                
                                <xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
                                    xmlns:{prefix}=""{urins}"">
                                  <xsl:output method='xml' indent='yes'/>
                                  <xsl:preserve-space elements='*'/>
                                    <xsl:template match=""{prefix}:*"">
                                        <xsl:copy>
                                            <xsl:apply-templates select=""node()|@*""/>
                                        </xsl:copy>
                                    </xsl:template>
                                    <xsl:template match=""*"">
                                        <xsl:element name=""{prefix}:{{local-name()}}"">
                                            <xsl:apply-templates select=""node()|@*""/>
                                        </xsl:element>
                                    </xsl:template>
                                  <xsl:template match='@*'>
                                    <xsl:attribute name='{{local-name(.)}}'>
                                      <xsl:value-of select='.'/>
                                    </xsl:attribute>
                                  </xsl:template>
                                  <xsl:template match='comment()'>
                                     <xsl:copy />
                                  </xsl:template>
                                </xsl:stylesheet>";

                    using (var stringReader = new StringReader(xslt))
                    {
                        using (XmlReader xsltReader = XmlReader.Create(stringReader))
                        {
                            var transformer = new XslCompiledTransform();
                            transformer.Load(xsltReader);
                            using (XmlReader oldDocumentReader = oldDocument.CreateReader())
                            {
                                using (var newDocumentWriter = newDocument.CreateWriter())
                                {
                                    transformer.Transform(oldDocumentReader, newDocumentWriter);
                                }
                            }
                        }
                    }

                    result = newDocument.ToString();
                }
                break;
            case false:
                xslt = $@"<?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' indent='yes'/>
                                  <xsl:preserve-space elements='*'/>
                                  <xsl:template match='*'>
                                    <xsl:element name='{{local-name(.)}}' xmlns='{urins}'>
                                      <xsl:apply-templates select='@* | node()'/>
                                    </xsl:element>
                                  </xsl:template>
                                  <xsl:template match='@*'>
                                    <xsl:attribute name='{{local-name(.)}}'>
                                      <xsl:value-of select='.'/>
                                    </xsl:attribute>
                                  </xsl:template>
                                  <xsl:template match='comment()'>
                                     <xsl:copy />
                                  </xsl:template>
                                </xsl:stylesheet>";
                using (var stringReader = new StringReader(xslt))
                {
                    using (XmlReader xsltReader = XmlReader.Create(stringReader))
                    {
                        var transformer = new XslCompiledTransform();
                        transformer.Load(xsltReader);
                        using (XmlReader oldDocumentReader = oldDocument.CreateReader())
                        {
                            using (var newDocumentWriter = newDocument.CreateWriter())
                            {
                                transformer.Transform(oldDocumentReader, newDocumentWriter);
                            }
                        }

                    }
                }
                break;
        }

        using (var stringWriter = new StringWriter())
        {
            // Make sure the indentation is preserved
            var xmlSettings = new XmlWriterSettings();
            xmlSettings.OmitXmlDeclaration = true;
            xmlSettings.Indent = true;
            xmlSettings.IndentChars = "\t";
            xmlSettings.NewLineHandling = NewLineHandling.Entitize;
            using (var xmlWriter = XmlWriter.Create(stringWriter, xmlSettings))
            {
                newDocument.Save(xmlWriter);
            }
            result = stringWriter.ToString();
        }

        // only for testing
        result = result.Replace("\"", "'").Trim();
        //content = content.Trim();

        hasChanged = content != result;

        return result;
    }

but it's doing some changes I don't want it to do:

  • Add additional space at the end of the self-closed element: <f:Cell Name='Option1Label'/> to <f:Cell Name='Option1Label' /> and also changing the indentation of empty lines. enter image description here

Any suggestion?

CodePudding user response:

As for empty elements being serialized with e.g. <foo /> instead of <foo/>, well, yes, that is the default empty element serialization the Microsoft's XML stack (XmlWriter) in .NET does, if you really want to enforce your own rules you would need to implement your own XmlWriter outputting the wanted format.

As for the indentation changing, I would start by not using xsl:output indent="yes" and of course also not an XmlWriter that enforces indentation. It might also be easier to control such issues if you let the XSLT processor transform to a file or stream instead of to an tree model like XDocument.

CodePudding user response:

First decide whether you want the XSLT processor to do the serialization, or the XmlWriter. Currently it's being done by the XmlWriter, so the XSLT serialization parameters are ignored.

Second, whichever one you choose, make sure indentation is switched off at that level.

  • Related