处理两个 XML 文件时无法使 XSLT 节点副本工作 [英] Can't get XSLT node copy to work when dealing with two XML files

查看:24
本文介绍了处理两个 XML 文件时无法使 XSLT 节点副本工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个 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>

几个问题:

  1. 我的 XSLT 有什么问题?
  2. 调试按键调用的技术是什么?.

  1. What's wrong with my XSLT ?
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆