删除外键

时间:2012-10-01 15:38:19

标签: xslt xslt-2.0

我有以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的行。我根据我看到的例子尝试了几件事,但是无法正常工作。

3 个答案:

答案 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')) &lt; 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')) &gt;= 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>