如何组合这两个xsl文件

时间:2013-04-10 07:34:44

标签: xml xslt schematron

我有一个具有抽象模式的schematron文件,我想使用xsl文件将此文件转换为没有抽象模式的文件,所有抽象模式都是实例。 问题是当我实例化抽象模式时,如果我在<pattern>中提供@id属性一切正常。没有@id,抽象模式中的paremeter无法正确替换 schematron文件如下

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron">
    <title>Table abstract patterns</title>

    <pattern abstract="true" id="table">
        <rule context="$table">
            <assert test="$row">A table has at least one row</assert>
        </rule>
        <rule context="$row">
            <assert test="$cell">A table row has at least one cell</assert>
        </rule>
    </pattern>

    <pattern is-a="table">
        <param name="table" value="table"/>
        <param name="row"  value="tr"/>
        <param name="cell"  value="td"/>
    </pattern>
</schema>

xsl文件是

<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:iso="http://purl.oclc.org/dsdl/schematron"  
    xmlns:nvdl="http://purl.oclc.org/dsdl/nvdl"  


    xmlns:iae="http://www.schematron.com/namespace/iae" 

      >

    <xslt:param name="schema-id"></xslt:param>


    <!-- Driver for the mode -->
    <xsl:template match="/">
        <xsl:apply-templates select="." mode="iae:go" />
    </xsl:template> 


    <!-- ================================================================================== -->
    <!-- Normal processing rules                                                            -->
    <!-- ================================================================================== -->
    <!-- Output only the selected schema --> 
    <xslt:template match="iso:schema" >
        <xsl:if test="string-length($schema-id) =0 or @id= $schema-id ">
            <xslt:copy>
                <xslt:copy-of select="@*" />
                <xslt:apply-templates  mode="iae:go" /> 
            </xslt:copy>
        </xsl:if>
    </xslt:template>


    <!-- Strip out any foreign elements above the Schematron schema .
        -->
    <xslt:template match="*[not(ancestor-or-self::iso:*)]"     mode="iae:go"  >
       <xslt:apply-templates  mode="iae:go" />
    </xslt:template>


    <!-- ================================================================================== -->
    <!-- Handle Schematron abstract pattern preprocessing                                   -->
    <!-- abstract-to-real calls
            do-pattern calls 
                macro-expand calls 
                    multi-macro-expand
                        replace-substring                                                   -->
    <!-- ================================================================================== -->

    <!--
        Abstract patterns allow you to say, for example

        <pattern name="htmlTable" is-a="table">
            <param name="row" value="html:tr"/>
            <param name="cell" value="html:td" />
            <param name="table" value="html:table" />
        </pattern>

        For a good introduction, see Uche Ogbujii's article for IBM DeveloperWorks
        "Discover the flexibility of Schematron abstract patterns"
          http://www-128.ibm.com/developerworks/xml/library/x-stron.html
        However, note that ISO Schematron uses @name and @value attributes on
        the iso:param element, and @id not @name on the pattern element.

    -->

    <!-- Suppress declarations of abstract patterns -->
    <xslt:template match="iso:pattern[@abstract='true']"  mode="iae:go"  >
        <xslt:comment>Suppressed abstract pattern <xslt:value-of select="@id"/> was here</xslt:comment> 
    </xslt:template> 


    <!-- Suppress uses of abstract patterns -->
    <xslt:template match="iso:pattern[@is-a]"  mode="iae:go" >

        <xslt:comment>Start pattern based on abstract <xslt:value-of select="@is-a"/></xslt:comment>

        <xslt:call-template name="iae:abstract-to-real" >
            <xslt:with-param name="caller" select="@id" />
            <xslt:with-param name="is-a" select="@is-a" />
        </xslt:call-template>

    </xslt:template>



    <!-- output everything else unchanged -->
    <xslt:template match="*" priority="-1"  mode="iae:go" >
        <xslt:copy>
            <xslt:copy-of select="@*" />
            <xslt:apply-templates mode="iae:go"/> 
        </xslt:copy>
    </xslt:template>

    <!-- Templates for macro expansion of abstract patterns -->
    <!-- Sets up the initial conditions for the recursive call -->
    <xslt:template name="iae:macro-expand">
        <xslt:param name="caller"/>
        <xslt:param name="text" />
        <xslt:call-template name="iae:multi-macro-expand">
            <xslt:with-param name="caller" select="$caller"/>
            <xslt:with-param name="text" select="$text"/>
            <xslt:with-param name="paramNumber" select="1"/>
        </xslt:call-template>

    </xslt:template>

    <!-- Template to replace the current parameter and then
       recurse to replace subsequent parameters. -->

    <xslt:template name="iae:multi-macro-expand">
        <xslt:param name="caller"/>
        <xslt:param name="text" />
        <xslt:param name="paramNumber" />


        <xslt:choose>
            <xslt:when test="//iso:pattern[@id=$caller]/iso:param[ $paramNumber]">

                <xslt:call-template name="iae:multi-macro-expand">
                    <xslt:with-param name="caller" select="$caller"/>   
                    <xslt:with-param name="paramNumber" select="$paramNumber + 1"/>     
                    <xslt:with-param name="text" >
                        <xslt:call-template name="iae:replace-substring">
                            <xslt:with-param name="original" select="$text"/>
                            <xslt:with-param name="substring"
                            select="concat('$', //iso:pattern[@id=$caller]/iso:param[ $paramNumber ]/@name)"/>
                            <xslt:with-param name="replacement"
                                select="//iso:pattern[@id=$caller]/iso:param[ $paramNumber ]/@value"/>          
                        </xslt:call-template>
                    </xslt:with-param>                      
                </xslt:call-template>
            </xslt:when>
            <xslt:otherwise><xslt:value-of select="$text" /></xslt:otherwise>       

        </xslt:choose>
    </xslt:template>


    <!-- generate the real pattern from an abstract pattern + parameters-->
    <xslt:template name="iae:abstract-to-real" >
        <xslt:param name="caller"/>
        <xslt:param name="is-a" />
        <xslt:for-each select="//iso:pattern[@id= $is-a]">
        <xslt:copy>

            <xslt:choose>
              <xslt:when test=" string-length( $caller ) = 0">
              <xslt:attribute name="id"><xslt:value-of select="concat( generate-id(.) , $is-a)" /></xslt:attribute>
              </xslt:when>
              <xslt:otherwise>
                <xslt:attribute name="id"><xslt:value-of select="$caller" /></xslt:attribute>
              </xslt:otherwise>
            </xslt:choose> 

            <xslt:apply-templates select="*|text()" mode="iae:do-pattern"    >
                <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
            </xslt:apply-templates> 

        </xslt:copy>
        </xslt:for-each>
    </xslt:template>


    <!-- Generate a non-abstract pattern -->
    <xslt:template mode="iae:do-pattern" match="*">
        <xslt:param name="caller"/>
        <xslt:copy>
            <xslt:for-each select="@*[name()='test' or name()='context' or name()='select']">
                <xslt:attribute name="{name()}">
                <xslt:call-template name="iae:macro-expand">
                        <xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
                        <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
                    </xslt:call-template>
                </xslt:attribute>
            </xslt:for-each>    
            <xslt:copy-of select="@*[name()!='test'][name()!='context'][name()!='select']" />
            <xsl:for-each select="node()">
                <xsl:choose>
                    <!-- Experiment: replace macros in text as well, to allow parameterized assertions
                        and so on, without having to have spurious <iso:value-of> calls and multiple
                        delimiting -->
                    <xsl:when test="self::text()">  
                        <xslt:call-template name="iae:macro-expand">
                            <xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
                            <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
                        </xslt:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xslt:apply-templates select="." mode="iae:do-pattern">
                            <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
                        </xslt:apply-templates>     
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>         
        </xslt:copy>
    </xslt:template>

    <!-- UTILITIES --> 
    <!-- Simple version of replace-substring function -->
    <xslt:template name="iae:replace-substring">
        <xslt:param name="original" />    
        <xslt:param name="substring" />   
        <xslt:param name="replacement" select="''"/>

  <xsl:choose>
    <xsl:when test="not($original)" /> 
    <xsl:when test="not(string($substring))">
      <xsl:value-of select="$original" />
    </xsl:when> 
        <xsl:when test="contains($original, $substring)">
          <xsl:variable name="before" select="substring-before($original, $substring)" />
          <xsl:variable name="after" select="substring-after($original, $substring)" />

          <xsl:value-of select="$before" />
          <xsl:value-of select="$replacement" />
          <!-- recursion -->
          <xsl:call-template name="iae:replace-substring">
            <xsl:with-param name="original" select="$after" />
            <xsl:with-param name="substring" select="$substring" />
            <xsl:with-param name="replacement" select="$replacement" /> 
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <!-- no substitution -->
            <xsl:value-of select="$original" />
        </xsl:otherwise>
      </xsl:choose> 
</xslt:template>

</xslt:stylesheet>

我的预期结果是

    <?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron">
    <title>Table abstract patterns</title>

    <pattern id="table1">
        <rule context="table">
            <assert test="tr">A table has at least one row</assert>
        </rule>
        <rule context="tr">
            <assert test="td">A table row has at least one cell</assert>
        </rule>
    </pattern>
</schema>

现在我有一个预处理xsl如下,如果我先使用这个,然后再使用上面的那个,我会得到我想要的东西

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
    version="1.0"    
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:iso="http://purl.oclc.org/dsdl/schematron"  
    xmlns:nvdl="http://purl.oclc.org/dsdl/nvdl"  


    xmlns:iae="http://www.schematron.com/namespace/iae" 

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

    <xsl:template match="iso:pattern[not(@id)]">

        <xslt:comment>Add @id for pattern </xslt:comment>
        <xsl:copy>
            <xslt:comment>Add @id for pattern </xslt:comment>
            <xsl:attribute name="id">
                <xslt:value-of select="generate-id(.) "/>
            </xsl:attribute>
            <xsl:apply-templates  select="node() | @*"/>
        </xsl:copy>

    </xsl:template>

</xsl:stylesheet>

如何将这两个文件组合在一起?

1 个答案:

答案 0 :(得分:0)

使用以下命令更改模板:

  <xslt:template name="iae:abstract-to-real" >
    <xslt:param name="caller"/>
    <xslt:param name="is-a" />
    <xslt:for-each select="//iso:pattern[@id= $is-a]">
      <xslt:copy>

        <xslt:choose>
          <xslt:when test=" string-length( $caller ) = 0">
            <xslt:attribute name="id"><xslt:value-of select="concat( generate-id(.) , $is-a)"/></xslt:attribute>
          </xslt:when>
          <xslt:otherwise>
            <xslt:attribute name="id"><xslt:value-of select="$caller" /></xslt:attribute>
          </xslt:otherwise>
        </xslt:choose> 

        <xslt:apply-templates select="*|text()" mode="iae:do-pattern"    >
          <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
        </xslt:apply-templates> 

      </xslt:copy>
    </xslt:for-each>
    <xslt:for-each select="//iso:pattern[not(@id)]">
      <xslt:copy>

        <xslt:choose>
          <xslt:when test=" string-length( $caller ) = 0"/>
          <xslt:otherwise>
            <xslt:attribute name="id"><xslt:value-of select="$caller" /></xslt:attribute>
          </xslt:otherwise>
        </xslt:choose> 

        <xslt:apply-templates select="*|text()" mode="iae:do-pattern"    >
          <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
        </xslt:apply-templates> 

      </xslt:copy>
    </xslt:for-each>
  </xslt:template>