2

I have DB tables stored in XML format that have a FK based on two columns (Table2 has FK to Table1 based on ID and TYPE).


    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>


I will have two XSLT files to delete rows in each XML file. Table2 will be processed first. I want to delete the row in Table2 where when joined with Table1 CONFIG=Z (ie, delete rows where (ID=2 and Type=A) and (ID=3 and Type=A), but I need to figure this out only knowing I want to delete records where CONFIG=Z). Table1 will then be processed to delete rows where CONFIG=Z, which I was able to figure out.

I think the XSLT that will be applied to Table2 needs to read in Table1 XML (xsl:variable name="table1Rows" select="document('Table1.xml')/Table/Row"/>). After that I'm lost on how to delete rows in Table2 where CONFIG=Z. I've tried several things based on examples I saw, but couldn't get anything to work.

4

3 回答 3

0

With XSLT 2.0 define a key and cross-reference the elements, then simply do an identity transformation to copy nodes plus a template that suppresses the copying for those Row elements where the key function call finds a Row in the other document with the CONFIG being 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] For completeness, I tested the following complete sample with both Saxon 9.4 as well as AltovaXML successfully:

<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>

On request in comment I also add an XSLT 1.0 stylesheet:

<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>
于 2012-10-01T17:25:47.253 回答
0

Martin's solution is correct, given the original question and should be accepted.

In reference to the OP's request for an additional XSLT 1.0 solution, here is a polyglot. This style-sheet, a minor variation of Martin's solution, works on XSLT 2.0 processors and probably most XSLT 1.0 processors.

<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>

Caveat

This style-sheet was not tested.

于 2012-10-02T03:56:06.533 回答
0

The answers provided by Martin work and are probably the best solutions possible. For XSLT 1.0 I had come up with the following that seems to run faster, but is not as elegant. For this solution I knew that the only possible TYPE for CONFIG=Z is 'A'. (Note there could be a typo below since I'm running the XSLT on another machine and retyped it here with the mock column names/values.)


    <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>

于 2012-10-02T14:16:09.893 回答