我有以XML格式存储的数据库表,它们具有基于两列的FK(表2基于ID和TYPE具有FK到表1)。
Table1.xml
<Table>
<Row>
<ID>1</ID>
<TYPE>A</TYPE>
<CONFIG>Y</CONFIG>
...
</Row>
<Row>
<ID>2</ID>
<TYPE>A</TYPE>
<CONFIG>Z</CONFIG>
...
</Row>
<Row>
<ID>1</ID>
<TYPE>B</TYPE>
<CONFIG>X</CONFIG>
...
</Row>
<Row>
<ID>3</ID>
<TYPE>A</TYPE>
<CONFIG>Z</CONFIG>
...
</Row>
</Table>
Table2.xml
<Table>
<Row>
<ID>1</ID>
<TYPE>A</TYPE>
...
</Row>
<Row>
<ID>2</ID>
<TYPE>A</TYPE>
...
</Row>
<Row>
<ID>1</ID>
<TYPE>B</TYPE>
...
</Row>
<Row>
<ID>3</ID>
<TYPE>A</TYPE>
...
</Row>
</Table>
我将有两个XSLT文件来删除每个XML文件中的行。表2将首先处理。我想删除Table2中与Table1 CONFIG = Z连接的行(即删除行(ID = 2和Type = A)和(ID = 3和Type = A),但我只需要弄清楚这一点知道我想删除CONFIG = Z的记录。然后将处理Table1以删除CONFIG = Z的行,我能够弄清楚。
我认为将应用于Table2的XSLT需要读入Table1 XML(xsl:variable name =“table1Rows”select =“document('Table1.xml')/ Table / Row”/&gt;)。之后,我迷失了如何删除Table2中CONFIG = Z的行。我根据我看到的例子尝试了几件事,但是无法正常工作。
答案 0 :(得分:0)
使用XSLT 2.0定义一个键并交叉引用元素,然后简单地进行身份转换以复制节点以及一个模板,该模板禁止复制那些键函数调用在其中找到一行的Row
元素。 CONFIG为Z
的其他文件:
<xsl:variable name="table1" select="doc('Table1.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row[key('r-by-id-and-type', concat(ID, '|', TYPE), $table1)/CONFIG = 'Z']"/>
[edit]为了完整性,我成功地使用Saxon 9.4和AltovaXML测试了以下完整样本:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:variable name="table1" select="doc('table1.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row[key('r-by-id-and-type', concat(ID, '|', TYPE), $table1)/CONFIG = 'Z']"/>
</xsl:stylesheet>
根据评论请求,我还添加了一个XSLT 1.0样式表:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="table1" select="document('test2012100102.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row">
<xsl:variable name="this" select="."/>
<xsl:for-each select="$table1">
<xsl:if test="not(key('r-by-id-and-type', concat($this/ID, '|', $this/TYPE))/CONFIG = 'Z')">
<xsl:copy-of select="$this"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
马丁的解决方案是正确的,给出了原始问题,应该被接受。
关于OP对额外XSLT 1.0解决方案的请求,这里是一个多语言。这个样式表是Martin解决方案的一个小变种,适用于XSLT 2.0处理器,可能是大多数XSLT 1.0处理器。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:variable name="table1" select="doc('table1.xml')"/>
<xsl:key name="r-by-id-and-type" match="Table/Row" use="concat(ID, '|', TYPE)"/>
<xsl:template match="@*|node()" name="ident">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="Row"
use-when="number(system-property('xsl:version')) < 2" priority="2">
<xsl:variable name="row" select="." />
<xsl:variable name="id-type" select="concat(ID, '|', TYPE)" />
<xsl:for-each select="$table1">
<xsl:if test="not( key('r-by-id-and-type', $id-type))">
<xsl:for-each select="$row">
<xsl:call-template name="ident" />
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template
match="Row"
use-when="number(system-property('xsl:version')) >= 2" priority="1">
<xsl:if test="not( key('r-by-id-and-type', concat(ID, '|', TYPE), $table1))">
<xsl:call-template name="ident" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
此样式表未经过测试。
答案 2 :(得分:0)
Martin提供的答案可能是最好的解决方案。对于XSLT 1.0,我提出了以下似乎运行得更快,但并不那么优雅。对于这个解决方案,我知道CONFIG = Z唯一可能的TYPE是'A'。 (注意,由于我在另一台机器上运行XSLT并在此处使用模拟列名称/值重新输入,因此可能会出现一个拼写错误。)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="table1_Z_rows" select="document('table1.xml')/Table/Row[CONFIG='Z']"/>
<xsl:template match="Row">
<xsl:choose>
<xsl:when test="TYPE != 'A'">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="not(ID = $table1_Z_rows/ID)">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>