XSLT to generate another XSLT script

后端 未结 3 1665
感动是毒
感动是毒 2021-02-20 13:51

In this thread I refer to my last thread: Convert XML to CSV using XSLT - dynamic columns.

The XSLT script in the refered thread works fine but with a large

相关标签:
3条回答
  • 2021-02-20 14:15

    See an actual example of an XSLT transformation that produces a stylesheet for another XSLT transformation here:

    http://dnovatchev.wordpress.com/2006/10/21/a-stylesheet-to-write-xslt-code/

    0 讨论(0)
  • 2021-02-20 14:16

    Rather than a two-external-phase solution (meaning a style-sheet that writes a style-sheet that gets executed), I think you would be better served by a version of Tim's solution that performs better at scale. Please measure the performance of this solution with your 'large XML document' as input.

    This XSLT 1.0 style-sheet...

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" />
    
    <xsl:key name="kTypes" match="Type" use="." />  
    <xsl:variable name="distinct-types"
      select="/*/Person/FamilyMembers/FamilyMember/Type[
      generate-id()=generate-id(key('kTypes',.)[1])]" />
    
    <xsl:template match="/">
      <xsl:value-of select="'Name;'" />
      <xsl:for-each select="$distinct-types">
        <xsl:value-of select="." />
        <xsl:if test="position() &lt; last()">
          <xsl:value-of select="';'" />
        </xsl:if>  
      </xsl:for-each>
      <xsl:value-of select="'&#x0A;'" />
      <xsl:apply-templates select="*/Person" />
    </xsl:template>
    
    <xsl:template match="Person">
      <xsl:value-of select="concat(Name,';')" />
      <xsl:variable name="family" select="FamilyMembers/FamilyMember" />
      <xsl:for-each select="$distinct-types">
        <xsl:variable name="type" select="string(.)" />
        <xsl:value-of select="$family/self::*[Type=$type]/Name" />
        <xsl:if test="position() &lt; last()">
          <xsl:value-of select="';'" />
        </xsl:if>  
      </xsl:for-each>
      <xsl:value-of select="'&#x0A;'" />
    </xsl:template>
    
    </xsl:stylesheet>
    

    ...will transform this input (or others efficiently at scale) ...

    <t>
    <Person>
        <Name>John</Name>
        <FamilyMembers>
            <FamilyMember>
                <Name>Lisa</Name>
                <Type>Sister</Type>
            </FamilyMember>
            <FamilyMember>
                <Name>Tom</Name>
                <Type>Brother</Type>
            </FamilyMember>
        </FamilyMembers>
    </Person>
    <Person>
        <Name>Daniel</Name>
        <FamilyMembers>
            <FamilyMember>
                <Name>Peter</Name>
                <Type>Father</Type>
            </FamilyMember>
        </FamilyMembers>
    </Person>
    </t>
    

    ... and yield text...

    Name;Sister;Brother;Father
    John;Lisa;Tom;
    Daniel;;;Peter
    
    0 讨论(0)
  • 2021-02-20 14:17

    To write one XSLT that outputs another you either need to generate the output elements using <xsl:element>, e.g.

    <xsl:element name="xsl:text">
    

    or use <xsl:namespace-alias> if you want to use literal result elements. The XSLT spec has an example:

    <xsl:stylesheet
      version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:fo="http://www.w3.org/1999/XSL/Format"
      xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias">
    
    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
    
    <xsl:template match="/">
      <axsl:stylesheet>
        <xsl:apply-templates/>
      </axsl:stylesheet>
    </xsl:template>
    

    Any <axsl:...> elements in the stylesheet will become <xsl:...> in the output.

    0 讨论(0)
提交回复
热议问题