IndentXml CF UDF

I had a need to fix indentation of some XML today, and a quick Googling didn't turn up much help. So I wrote a little UDF that will take an XML string and return it with all the tags nicely indented:


  
  
  
  
  
  
  
  
  
  )\s*(<|$)", "\1#chr(10)#\2", "all")) />
  
  
  
    
    
    
    ">
      
      "
        OR REFindNoCase("<([a-z][a-z0-9_-]*).*", line) />
      
        
        
      
      
      
        
      
    
      
      
    
  
  

There's nothing XML-ish about the implementation, as you can see, so you can happily feed non-XML tag based markup, as long as it uses '<' and '>' as tag delimiters in the XML fashion. Just don't expect to get good formatting if you don't have tags that follow the XML spec (e.g. CFELSE).  Also, it doesn't account for open tags (or closing tags) that are split across multiple lines. That wasn't a case I cared about, and I don't know that you can solve it correctly without actually parsing at least CDATA blocks out of the XML.

Update (2010-03-10): I've made a slight change to isSelfClose to include tags that don't use an XML self-close, but do have a closing tag on the same line, to avoid extra indentation on following lines.  This change is reflected in the above. https://www.s188bet.com

Update (2010-07-30): Jean Moniatte, via cflib.org,  noticed that my regex doesn't handle element names that contains dashes or underscores (both of which are legal).  I've addressed that issue above, and Ray has updated the UDF at cflib.org as well.

Update (2012-09-28): Per a question that got to be through cflib.org, I'm explicitly licensing this UDF under the MIT license.

2 responses to “IndentXml CF UDF”

  1. Joshua

    I usually use xsl transforms. Although that may not have been useful for what you wanted? There are several variants on this available on the web.

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:param name="indent-increment" select="' '" />

    <xsl:template match="*">
    <xsl:param name="indent" select="'&#xA;'"/>

    <xsl:value-of select="$indent"/>

    <xsl:copy>
    <xsl:copy-of select="@*" />
    <xsl:apply-templates>
    <xsl:with-param name="indent"
    select="concat($indent, $indent-increment)"/>

    </xsl:apply-templates>
    <xsl:value-of select="$indent"/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="comment()|processing-instruction()">

    <xsl:copy />
    </xsl:template>

    <!-- WARNING: this is dangerous. Handle with care -->
    <xsl:template match="text()[normalize-space(.)='']"/>

    </xsl:stylesheet>