首页 > 解决方案 > XSLT 将属性从节点转换为另一个节点的元素并将它们从源节点中删除

问题描述

给定这个 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-3.6.xsd">
  <changeSet author="system (generated)"
           context="legacy"
           id="1537289247911-1"
           objectQuotingStrategy="LEGACY">
    <createTable remarks="Language-dependent texts."
                 tableName="AS_LANGUAGETEXT">
      <column name="TEXTID" remarks="Description identifier" type="NUMBER(9, 0)">
        <constraints primaryKey="true" primaryKeyName="PK_AS_LANGUAGETEXT"/>
      </column>
      <column name="LANGID"
                remarks="Language identifier"
                type="java.sql.Types.VARCHAR(2 ${byteVarcharType})">
        <constraints primaryKey="true" primaryKeyName="PK_AS_LANGUAGETEXT"/>
      </column>
      <column name="TEXT"
                remarks="Description"
                type="java.sql.Types.VARCHAR(4000 ${charVarcharType})"/>
    </createTable>
    <customChange>
      ...
    </customChange>
  </changeSet>
  <changeSet>
    <createTable>
      ...
    </createTable>
    <customChange>
      ...
    </customChange>
  </changeSet>
</databaseChangeLog>

我想:

所以最后它应该是这样的:

<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-3.6.xsd">
  <changeSet author="system (generated)"
           context="legacy"
           id="1537289247911-1"
           objectQuotingStrategy="LEGACY">
    <createTable tableName="AS_LANGUAGETEXT">
      <column name="TEXTID" type="NUMBER(9, 0)">
        <constraints primaryKey="true" primaryKeyName="PK_AS_LANGUAGETEXT"/>
      </column>
      <column name="LANGID"
                type="java.sql.Types.VARCHAR(2 ${byteVarcharType})">
        <constraints primaryKey="true" primaryKeyName="PK_AS_LANGUAGETEXT"/>
      </column>
      <column name="TEXT"
                type="java.sql.Types.VARCHAR(4000 ${charVarcharType})"/>
    </createTable>
    <customChange>
      ...
    </customChange>
  </changeSet>
  <changeSet id="621c99b7-eb65-462b-890c-014079e5b44c" author="system">
    <setTableRemarks tableName="AS_LANGUAGETEXT" remarks="Language-dependent texts." />
    <setColumnRemarks tableName="AS_LANGUAGETEXT" columnName="TEXTID" remarks="Description identifier" />
    <setColumnRemarks tableName="AS_LANGUAGETEXT" columnName="LANGID" remarks="Language identifier" />
    <setColumnRemarks tableName="AS_LANGUAGETEXT" columnName="LANGID" remarks="Description" />
  </changeSet>
  <changeSet>
    <createTable>
      ...
    </createTable>
    <customChange>
      ...
    </customChange>
  </changeSet>
  <changeSet>
    <setTableRemarks ... />
    <setColumnRemarks ... />
  </changeSet>
</databaseChangeLog>

编辑:我用这个模板做到了。只有我不知道该怎么做的是 uuid,因为 saxon-he 不支持对 java 的调用。因此,我使用了generate-id()函数而不是 uuid。

<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
               xpath-default-namespace="http://www.liquibase.org/xml/ns/dbchangelog">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

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

    <xsl:template match="changeSet[createTable]">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="createTable"/>
            <xsl:copy-of select="*[not(self::createTable)]"/>
        </xsl:copy>
        <xsl:element name="changeSet" namespace="http://www.liquibase.org/xml/ns/dbchangelog">
            <xsl:attribute name="id" select="generate-id()" />
            <xsl:attribute name="author">system</xsl:attribute>
            <xsl:element name="setTableRemarks" namespace="http://www.liquibase.org/xml/ns/dbchangelog">
                <xsl:attribute name="tableName" select="createTable//@tableName"/>
                <xsl:attribute name="remarks" select="createTable//@remarks"/>
            </xsl:element>
            <xsl:for-each select="createTable/column">
                <xsl:element name="setColumnRemarks" namespace="http://www.liquibase.org/xml/ns/dbchangelog">
                    <xsl:attribute name="tableName" select="../@tableName"/>
                    <xsl:attribute name="columnName" select="@name"/>
                    <xsl:attribute name="remarks" select="@remarks"/>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

    <xsl:template match="createTable/@remarks"/>
    <xsl:template match="createTable/column/@remarks"/>

</xsl:transform>

对于我正在使用的转换Saxon-HE:9.8.0-12(java)

标签: xsltsaxon

解决方案


UUID 可以在 XSLT 中实现。

例如,它已在此样式表中实现:https ://gist.github.com/azinneera/778f69ae6b0049b5edcd69da70072405 ,您可以将其包含或导入,然后使用它的uuid:get-uuid()方法。

假设它在本地保存为uuid-gen.xsl,应用于您的样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:uuid="http://www.uuid.org" 
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xpath-default-namespace="http://www.liquibase.org/xml/ns/dbchangelog">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <xsl:include href="uuid-gen.xsl"/>

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

    <xsl:template match="changeSet[createTable]">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="createTable"/>
            <xsl:copy-of select="*[not(self::createTable)]"/>
        </xsl:copy>
        <changeSet id="{uuid:get-uuid(.)}" author="system">
            <setTableRemarks>
                <xsl:copy-of select="createTable//(@tableName,@remarks)"/>
            </setTableRemarks>
            <xsl:for-each select="createTable/column">
                <setColumnRemarks>
                    <xsl:copy-of select="../@tableName"/>
                    <xsl:attribute name="columnName" select="@name"/>
                    <xsl:copy-of select="@remarks"/>
                </setColumnRemarks>
            </xsl:for-each>
        </changeSet>
    </xsl:template>

    <xsl:template match="createTable/@remarks"/>
    <xsl:template match="createTable/column/@remarks"/>  
</xsl:stylesheet>

推荐阅读