我有两个XML文件:
data1.xml
<?xml version="1.0" encoding="UTF-8"?>
<tables>
<table>
<row>
<cell colname="1">A</cell>
<cell colname="2">
<carType>Sedan</carType>
<gasType>Gasoline</gasType>
</cell>
<cell colnane="4">B</cell>
<cell colname="5">C</cell>
</row>
<row>
<cell colname="1">A1</cell>
<cell colname="2">
<carType>Truck</carType>
<gasType>Diesel</gasType>
</cell>
<cell colname="4">B1</cell>
<cell colname="5">C1</cell>
</row>
</table>
</tables>
data2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tables>
<table>
<row>
<cell colname="1">A</cell>
<cell colname="2">
<carType>SedanXYZ</carType>
<gasType>GasolineXYZ</gasType>
</cell>
<cell colname="4">B</cell>
<cell colname="5">C</cell>
</row>
<row>
<cell colname="1">A2</cell>
<cell colname="2">
<carType>Motorcycle</carType>
<gasType>Gasoline</gasType>
</cell>
<cell colname="4">U</cell>
<cell colname="5">Z</cell>
</row>
<row>
<cell colname="1">A1</cell>
<cell colname="2">
<carType>TruckXYZ</carType>
<gasType>DieselXYZ</gasType>
</cell>
<cell colname="4">B1</cell>
<cell colname="5">C1</cell>
</row>
</table>
</tables>
基本上我想将dataname =“2”中包含的内容从data2.xml复制到data1.xml,并保持data1.xml中的其余数据相同。找到相等性的关键是colname =“4”和colname =“5”。我的XSLT看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>
<xsl:param name="doc2"/>
<xsl:template match="/">
<xsl:message>Starting off</xsl:message>
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="cell[@colname='2']">
<xsl:variable name="key-value">
<xsl:call-template name="key-value"/>
</xsl:variable>
<xsl:for-each select="document($doc2)//row">
<xsl:if test="key('keyx', $key-value)">
<xsl:copy-of select="cell[@colname='2']"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- Just copy any other elements, attributes, etc. -->
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="keyx" match="row"
use="concat(cell[@colname='4'], cell[@colname='5'])"/>
<!-- This template retrives the key value for an element -->
<xsl:template name="key-value">
<xsl:value-of select="concat(../cell[@colname='4'],../cell[@colname='5'])"/>
</xsl:template>
</xsl:stylesheet>
我期待的结果:
<?xml version="1.0" encoding="iso-8859-1"?>
<tables>
<table>
<row>
<cell colname="1">A</cell>
<cell colname="2">
<carType>SedanXYZ</carType>
<gasType>GasolineXYZ</gasType>
</cell>
<cell colname="4">B</cell>
<cell colname="5">C</cell>
</row>
<row>
<cell colname="1">A1</cell>
<cell colname="2">
<carType>TruckXYZ</carType>
<gasType>DieselXYZ</gasType>
</cell>
<cell colname="4">B1</cell>
<cell colname="5">C1</cell>
</row>
</table>
</tables>
BUT I'm getting incorrect output like this:
<?xml version="1.0" encoding="iso-8859-1"?>
<tables>
<table>
<row>
<cell colname="1">A</cell>
<cell colname="2">
<carType>SedanXYZ</carType>
<gasType>GasolineXYZ</gasType>
</cell>
<cell colname="2">
<carType>Motorcycle</carType>
<gasType>Gasoline</gasType>
</cell>
<cell colname="2">
<carType>TruckXYZ</carType>
<gasType>DieselXYZ</gasType>
</cell>
<cell colname="4">B</cell>
<cell colname="5">C</cell>
</row>
<row>
<cell colname="1">A1</cell>
<cell colname="2">
<carType>SedanXYZ</carType>
<gasType>GasolineXYZ</gasType>
</cell>
<cell colname="2">
<carType>Motorcycle</carType>
<gasType>Gasoline</gasType>
</cell>
<cell colname="2">
<carType>TruckXYZ</carType>
<gasType>DieselXYZ</gasType>
</cell>
<cell colname="4">B1</cell>
<cell colname="5">C1</cell>
</row>
</table>
</tables>
所以有几个问题:
调试密钥调用的技巧是什么?。
谢谢!。
约翰
答案 0 :(得分:2)
你的代码出了什么问题:你使用key()而没有第三个参数。第三个参数告诉系统您要搜索哪个文档。如果省略它,它将搜索包含上下文节点的文档,而您要搜索“其他”文档。通过这种任务,最好有两个包含两个文档节点的全局变量,因此您可以在它们之间轻松切换。
我个人使用xsl:for-each-group解决这种合并任务。在for-each-group的select属性中,选择两个文档中的所有相关元素。在for-each-group的主体中,如果current-group()包含单个元素,则输出该元素,否则根据root(.) is $doc-two
等测试决定输出哪一个。
答案 1 :(得分:1)
我认为你不能在这里使用密钥功能,因为你需要在$ doc2上创建一个密钥集,而XML Spy不允许我这样做。关于源XML的关键是不够的 所以我为你写了另一个解决方案,而不是使用密钥:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>
<xsl:param name="doc2"><xsl:copy-of select="document('C:\test\data2.xml')"/></xsl:param>
<xsl:template match="/">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="cell[@colname='2']">
<xsl:variable name="keyValue" select="concat(../cell[@colname='4'], ../cell[@colname='5'])"/>
<xsl:for-each select="$doc2/tables/table/row[concat(cell[@colname='4'], cell[@colname='5']) = $keyValue]">
<xsl:copy-of select="cell[@colname='2']"/>
</xsl:for-each>
</xsl:template>
<!-- Just copy any other elements, attributes, etc. -->
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
哦,顺便说一下,源文件中有几个colnane
错字。
编辑忘记了关键功能中的第三个参数:-(。所以添加
<xsl:key name="keyx" match="row" use="concat(cell[@colname='4'], cell[@colname='5'])"/>
并将for-each更改为
<xsl:for-each select="key('keyx', $keyValue, $doc2)">
<xsl:copy-of select="cell[@colname='2']"/>
</xsl:for-each>
将实现您的目标。
编辑2
好的,上面替换了colname =“2”单元格,但是当没有找到data2匹配时,不会留下data1。
请改用以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/>
<xsl:param name="doc2"/> <!-- supplied in parameter list in specific tool -->
<xsl:key name="keyx" match="row" use="concat(cell[@colname='4'], cell[@colname='5'])"/>
<xsl:template match="/">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="cell[@colname='2']">
<xsl:variable name="keyValue" select="concat(../cell[@colname='4'], ../cell[@colname='5'])"/>
<xsl:variable name="doc2Matches" select="key('keyx', $keyValue, document($doc2))"/>
<xsl:choose>
<xsl:when test="$doc2Matches">
<xsl:copy-of select="$doc2Matches[1]/cell[@colname='2']"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Just copy any other elements, attributes, etc. -->
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>