代码之家  ›  专栏  ›  技术社区  ›  bilak

XSLT从原始文件中删除已处理的/选择未处理的数据

  •  0
  • bilak  · 技术社区  · 6 年前

    嗨,我正在处理大型文件(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>
    

    我用的是XSLT2和SAXOM 9.8HE

    谢谢

    2 回复  |  直到 6 年前
        1
  •  1
  •   Tim C    6 年前

    而不是这样做…

    <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)" />
    
        2
  •  0
  •   Michael Kay    6 年前

    我不太清楚你所说的“未处理”是什么意思。您的意思是“不通过对xsl:apply-templates的任何调用选择”?当然,这不是同一回事,一个节点可以使用xsl:for-each等来处理。另外,我怀疑您只对那些不以这种方式“处理”的元素感兴趣,而对属性和名称空间等其他节点不感兴趣。

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