Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Can';在处理两个XML文件时,不要让XSLT节点副本工作_Xslt_Xslt 2.0 - Fatal编程技术网

Can';在处理两个XML文件时,不要让XSLT节点副本工作

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

我有两个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>
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
所以有几个问题:

  • 我的XSLT有什么问题
  • 调试键调用的技术是什么

    谢谢你

    约翰


  • 我认为您不能在这里使用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