XSLT change/override attribute on copy-of not applied (using saxon )

杀马特。学长 韩版系。学妹 提交于 2020-01-06 12:26:10

问题


I have a xslt like this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:db="http://www.liquibase.org/xml/ns/dbchangelog"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml"  indent="yes" />
  <xsl:template match="/">    
      <xsl:for-each select="db:databaseChangeLog/db:changeSet"> 
          <xsl:if test="name(*[1])='createTable'">  
          <xsl:result-document  href="base/tables/{position()}_{name(*[1])}_{*[1]/@tableName}.xml">
           <databaseChangeLog 
                xmlns="http://www.liquibase.org/xml/ns/dbchangelog" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

                <xsl:copy-of select="."/>                       

                <xsl:copy-of select="../db:changeSet[name(*[1])='createIndex' and *[1]/@tableName= current()/*[1]/@tableName ]" />

            </databaseChangeLog> 
        </xsl:result-document>      
        </xsl:if> 
      </xsl:for-each>     
  </xsl:template>

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

    <xsl:template match="db:changeSet/@author" mode="copy">
        <xsl:attribute name="author">
            <xsl:value-of select="'sakhunzai'"/>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

XML partial file

<changeSet author="xxx (generated)" id="1358259674512-26">
        <createIndex indexName="category_id" tableName="teams" unique="false">
            <column name="audience_id"/>
        </createIndex>
</changeSet>
<changeSet author="xxx (generated)" id="1358259674512-29">
    <createIndex indexName="id" tableName="users" unique="false">
        <column name="id"/>
        <column name="career_lead_id"/>
    </createIndex>
</changeSet>

I want to override the attribute values of changeSet (author and id). Please help me fix the xslt.

Everything is working fine but @author atrribute value is not change in target xml files note: since xsltproc failed to do ,I switched to saxon java based processor e.g

java -jar /usr/local/liquibase/saxon/saxon9he.jar common.xml table.xslt

Working XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:db="http://www.liquibase.org/xml/ns/dbchangelog"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml"  indent="yes" />
  <xsl:template match="/">    
      <xsl:for-each select="db:databaseChangeLog/db:changeSet[db:createTable]"> 
          <xsl:result-document  href="base/tables/{position()}_{name(*[1])}_{*[1]/@tableName}.xml">
           <databaseChangeLog 
                xmlns="http://www.liquibase.org/xml/ns/dbchangelog" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

                <xsl:apply-templates select="." mode="copy"/>                       

                <xsl:apply-templates select="../db:changeSet[db:createIndex and *[1]/@tableName= current()/*[1]/@tableName ]"  mode="copy"/>

            </databaseChangeLog> 
        </xsl:result-document>
      </xsl:for-each>     
  </xsl:template>

  <xsl:template match="node()" mode="copy">
      <xsl:copy>
          <xsl:attribute name="author">sakhunzai</xsl:attribute>
           <xsl:copy-of select="@id|node()"/>
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

回答1:


<xsl:copy-of /> does not cause templates to be applied. It just creates an exact copy. How about changing this line

<xsl:template match="db:changeSet/@author">

to this:

<xsl:template match="db:changeSet/@author" mode="copy">

Adding this template:

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

and finally changing this:

<xsl:copy-of select="../db:changeSet[name(*[1])='createIndex' and *[1]/@tableName= current()/*[1]/@tableName ]">
    <xsl:copy-of select="."/>                       
</xsl:copy-of> 

To this:

<xsl:apply-templates 
   select=="../db:changeSet[name(*[1])='createIndex' and *[1]/@tableName = current()/*[1]/@tableName]" 
   mode="copy" />

As a side note, this looks a bit redundant:

<xsl:copy-of select="current()[name()='changeSet']">                        
    <xsl:copy-of select="."/>
</xsl:copy-of>

The current node necessarily has the name "changeSet", by virtue of the for-each loop. I believe this should suffice for that part:

<xsl:copy-of select="." />

Full XSLT:

<xsl:stylesheet xmlns:db="http://www.liquibase.org/xml/ns/dbchangelog"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml"  indent="yes" />
  <xsl:template match="/">    
      <xsl:for-each select="db:databaseChangeLog/db:changeSet"> 
          <xsl:if test="name(*[1])='createTable'">  
          <xsl:document href="base/tables/{position()}_{name(*[1])}_{*[1]/@tableName}.xml">
           <databaseChangeLog 
                xmlns="http://www.liquibase.org/xml/ns/dbchangelog" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

                    <xsl:copy-of select="." />                        

                    <xsl:apply-templates select="../db:changeSet[name(*[1])='createIndex' and *[1]/@tableName= current()/*[1]/@tableName ]" mode="copy" />
            </databaseChangeLog> 
        </xsl:document>     
        </xsl:if> 
      </xsl:for-each>     
  </xsl:template>

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

  <xsl:template match="db:changeSet/@author" mode="copy">
     <xsl:attribute name="author">
        <xsl:value-of select="'sakhunzai'"/>
      </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

I do think the XSLT could be further improved like the following. Give it a try if you like:

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

  <xsl:template match="db:changeSet" />

  <xsl:template match="db:changeSet[db:createTable]">
    <xsl:document href="base/tables/{position()}_{name(*[1])}_{*[1]/@tableName}.xml">
      <databaseChangeLog
           xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

        <xsl:copy-of select="." />

        <xsl:apply-templates select="../db:changeSet[db:createIndex and *[1]/@tableName = current()/*[1]/@tableName ]" mode="copy" />
      </databaseChangeLog>
    </xsl:document>
  </xsl:template>

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

  <xsl:template match="db:changeSet/@author" mode="copy">
    <xsl:attribute name="author">
      <xsl:value-of select="'sakhunzai'"/>
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>



回答2:


The xsl:copy-of element does not allow child elements. It looks like xsltproc is not validating your stylesheet carefully enough.



来源:https://stackoverflow.com/questions/14379447/xslt-change-override-attribute-on-copy-of-not-applied-using-saxon

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!