处理两个 XML 文件时无法使 XSLT 节点副本工作 [英] Can't get XSLT node copy to work when dealing with two XML files
问题描述
我有两个 XML 文件:
I have two XML files:
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>
基本上,我想将 colname="2" 中包含的任何内容从 data2.xml 复制到 data1.xml,并使 data1.xml 中的其余数据保持不变.找到相等的键是 colname="4" 和 colname="5".我的 XSLT 看起来像这样:
Basically I want to copy whatever contained in colname="2" from data2.xml to data1.xml and keep the rest of the data in data1.xml the same. The keys to find the equality are colname="4" and colname="5". My XSLT looks like this:
<?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>
几个问题:
- 我的 XSLT 有什么问题?
调试按键调用的技术是什么?.
- What's wrong with my XSLT ?
What's the technique to debug the key calls ?.
谢谢!
约翰
推荐答案
我认为您不能在这里使用 key 函数,因为您需要在 $doc2 上创建一个键集,而 XML Spy 不允许我这样做.而且源 XML 上的密钥是不够的.
所以我为你写了另一个解决方案,根本不使用密钥:
I think you cannot use the key function here, because you need to create a key set on $doc2 and XML Spy does not allow me to do so. And the key on the source XML will not suffice.
So I wrote another solution for you, not using key at all:
<?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
错别字.
Oh, and by the way, you have a couple of colnane
typo's in the source files.
EDIT 忘记了关键函数中的第三个参数 :-(.所以添加
EDIT forgot about the third argument in the key function :-(. So adding
<xsl:key name="keyx" match="row" use="concat(cell[@colname='4'], cell[@colname='5'])"/>
并将 for-each 更改为
and changing the for-each to
<xsl:for-each select="key('keyx', $keyValue, $doc2)">
<xsl:copy-of select="cell[@colname='2']"/>
</xsl:for-each>
将实现您的目标.
编辑 2
OK 以上替换了 colname="2" 单元格,但在没有找到 data2 匹配项时不保留 data1 单元格.
OK the above replaces colname="2" cells, but does not leave data1 ones when no data2 matches are found.
改为使用以下内容:
<?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>
这篇关于处理两个 XML 文件时无法使 XSLT 节点副本工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!