XSLT 从原始文件中删除 processed/select 未处理的数据

XSLT remove processed/select unprocessed data from original file

您好,我正在处理大文件(50k 行)并且需要了解未处理的节点。 我在考虑这个解决方案:

那么最好的方法是什么?如果需要提供更多详细信息,请告诉我。

这是我的样本 xml:

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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
                   http://www.liquibase.org/xml/ns/dbchangelog">

    <changeSet id="1" author="a">
        <createTable tableName="TABLE1">
            <column></column>
        </createTable>
    </changeSet>

    <changeSet id="1-1" author="a">
        <createSequence sequenceName="SEQ_TABLE1" />
    </changeSet>
    <changeSet id="4" author="A">
        <createTable tableName="TABLE4">
            <column></column>
        </createTable>
    </changeSet>
</databaseChangeLog>

这是 xslt 模板:

<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:variable name="coreTables"
                  select="('TABLE1','TABLE2')"/>


    <xsl:template match="node()[not(self::*)]">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

    <xsl:template match="databaseChangeLog">
        <!-- CORE-->
        <xsl:comment> CORE TABLES </xsl:comment>
        <xsl:apply-templates select="changeSet[createTable/@tableName=$coreTables]"/>
        <xsl:comment>CORE SEQUENCES</xsl:comment>
        <xsl:apply-templates
                select="changeSet[createSequence[starts-with(@sequenceName, 'SEQ_') and substring-after(@sequenceName, 'SEQ_') = $coreTables]]"/>
        <xsl:comment> CORE INDEXES </xsl:comment>
        <xsl:apply-templates select="changeSet[createIndex/@tableName=$coreTables]"/>
        <xsl:comment> CORE FOREIGN CONSTRAINTS </xsl:comment>
        <xsl:apply-templates select="changeSet[addForeignKeyConstraint/@baseTableName=$coreTables]"/>
        <xsl:comment> CORE VIEWS </xsl:comment>
        <xsl:apply-templates select="changeSet[createView/@viewName=$coreTables]"/>
    </xsl:template>

</xsl:transform>

我正在使用 xslt 2 和 saxom 9.8he

谢谢

而不是这样做...

<xsl:comment> CORE TABLES </xsl:comment>
<xsl:apply-templates select="changeSet[createTable/@tableName=$coreTables]"/>

执行此操作以保存所选元素

<xsl:variable name="tables" select="changeSet[createTable/@tableName=$coreTables]"/>
<xsl:apply-templates select="$tables" />

其他语句也类似。然后要获取 XML 中尚未匹配的元素,您可以这样做...

<xsl:apply-templates select="changeSet[not(some $set in ($tables | $sequences | $indexes | $fkeys | $views) satisfies $set is .)]" />

试试这个模板

<xsl:template match="databaseChangeLog">
    <!-- CORE-->
    <xsl:comment> CORE TABLES </xsl:comment>
    <xsl:variable name="tables" select="changeSet[createTable/@tableName=$coreTables]"/>
    <xsl:apply-templates select="$tables" />

    <xsl:comment>CORE SEQUENCES</xsl:comment>
    <xsl:variable name="sequences" select="changeSet[createSequence[starts-with(@sequenceName, 'SEQ_') and substring-after(@sequenceName, 'SEQ_') = $coreTables]]"/>
    <xsl:apply-templates select="$sequences"/>

    <xsl:comment> CORE INDEXES </xsl:comment>
    <xsl:variable name="indexes" select="changeSet[createIndex/@tableName=$coreTables]"/>
    <xsl:apply-templates select="$indexes"/>

    <xsl:comment> CORE FOREIGN CONSTRAINTS </xsl:comment>
    <xsl:variable name="fkeys" select="changeSet[addForeignKeyConstraint/@baseTableName=$coreTables]"/>
    <xsl:apply-templates select="$fkeys"/>

    <xsl:comment> CORE VIEWS </xsl:comment>
    <xsl:variable name="views" select="changeSet[addForeignKeyConstraint/@baseTableName=$coreTables]"/>
    <xsl:apply-templates select="$views"/>

    <xsl:comment> UNMATCHED </xsl:comment>
    <xsl:apply-templates select="changeSet[not(some $set in ($tables | $sequences | $indexes | $fkeys | $views) satisfies $set is .)]" />
</xsl:template>

编辑:感谢 Martin Honnen,最终表达式可以简化为...

<xsl:apply-templates select="changeSet except ($tables, $sequences, $indexes, $fkeys, $views)" />

我不太清楚你说的 "not processed" 是什么意思。你是说 "not selected by any call on xsl:apply-templates" 吗?这不是一回事,当然,一个节点可能会使用 xsl:for-each 等进行处理。此外,我怀疑您只对不是 "processed" 的元素感兴趣,而不是在其他节点中,例如属性和命名空间。

一种可能(或可能不)满足您的要求的方法是编写 TraceListener。如果您将 TraceListener 附加到您的转换,它会在每次指令更改上下文项时收到通知(这是 "being processed" 的另一个定义)。然后,您的 TraceListener 可以构建一个 Java 集合,其中包含所有被触摸的节点,然后可以在处理完成时将其与所有节点的集合进行区分。