Can';在处理两个XML文件时,不要让XSLT节点副本工作
我有两个XML文件:Can';在处理两个XML文件时,不要让XSLT节点副本工作,xslt,xslt-2.0,Xslt,Xslt 2.0,我有两个XML文件: data1.xml <?xml version="1.0" encoding="UTF-8"?> <tables> <table> <row> <cell colname="1">A</cell> <cell colname="2"> <carType>Sedan</c
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>
data1.xml
A.
轿车
汽油
B
C
A1
卡车
柴油机
地下一层
C1
data2.xml:
A.
塞丹克斯
汽油
B
C
A2
摩托车
汽油
U
Z
A1
卡车
柴油机
地下一层
C1
基本上,我希望将colname=“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>
A.
塞丹克斯
汽油
B
C
A1
卡车
柴油机
地下一层
C1
但我得到了如下不正确的输出:
A.
塞丹克斯
汽油
摩托车
汽油
卡车
柴油机
B
C
A1
塞丹克斯
汽油
摩托车
汽油
卡车
柴油机
地下一层
C1
所以有几个问题:
我认为您不能在这里使用key函数,因为您需要在$doc2上创建密钥集,而XMLSpy不允许我这样做。并且源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>
并将每个的
<xsl:for-each select="key('keyx', $keyValue, $doc2)">
<xsl:copy-of select="cell[@colname='2']"/>
</xsl:for-each>
将实现您的目标
编辑2
好的,上面替换colname=“2”单元格,但在未找到数据2匹配项时不保留数据1单元格
请改用以下方法:
<?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>
我认为您不能在这里使用key函数,因为您需要在$doc2上创建密钥集,而XMLSpy不允许我这样做。并且源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>
并将每个的
<xsl:for-each select="key('keyx', $keyValue, $doc2)">
<xsl:copy-of select="cell[@colname='2']"/>
</xsl:for-each>
将实现您的目标
编辑2
好的,上面替换colname=“2”单元格,但在未找到数据2匹配项时不保留数据1单元格
请改用以下方法:
<?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>
代码有什么问题:您使用的key()没有第三个参数。第三个参数告诉系统要搜索哪个文档。如果省略它,它将搜索包含上下文节点的文档,而您希望搜索“其他”文档。对于这种任务,最好有两个包含两个文档节点的全局变量,以便您可以在它们之间轻松切换
我个人使用xsl:for-each-group来处理这种合并任务。在“为每个组选择”属性中,从两个文档中选择所有相关元素。在for each group的主体中,如果current-group()包含单个元素,则输出该元素,否则根据测试决定输出哪个元素,例如
root(.)是$doc two
代码有什么问题:您使用的key()没有第三个参数。第三个参数告诉系统要搜索哪个文档。如果省略它,它将搜索包含上下文节点的文档,而您希望搜索“其他”文档。对于这种任务,最好有两个包含两个文档节点的全局变量,以便您可以在它们之间轻松切换
我个人使用xsl:for-each-group来处理这种合并任务。在“为每个组选择”属性中,从两个文档中选择所有相关元素。在for each group的主体中,如果current-group()包含单个元素,则输出该元素,否则根据测试决定输出哪个元素,例如
root(.)是$doc two
不要将Windows文件名用作doc()的参数。有些处理器会接受它们,但这是错误的:参数应该是URI,而不是依赖于平台的文件名。@MichaelKay的观点很好-但我只是出于快速测试的目的使用它。对于像我这样的本地文件系统文件,您建议使用什么作为uri?嗨,Maestro,看起来它无法运行,它抱怨“key()的第三个参数的必需项类型是node();提供的值具有项类型xs:untypedA