Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.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

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
Xml 如何使用XSLT2.0在两个文档之间合并元素?_Xml_Xslt - Fatal编程技术网

Xml 如何使用XSLT2.0在两个文档之间合并元素?

Xml 如何使用XSLT2.0在两个文档之间合并元素?,xml,xslt,Xml,Xslt,我在XML文档中有如下默认配置项: <ProgramConfig> <Fragment xml:lang="en" name="TargetSector">fragment/target_sector.xdp</Fragment> <Fragment xml:lang="fr" name="TargetSector">fragment/target_sector_fr.xdp</Fragment> <

我在XML文档中有如下默认配置项:

<ProgramConfig>

    <Fragment xml:lang="en" name="TargetSector">fragment/target_sector.xdp</Fragment>
    <Fragment xml:lang="fr" name="TargetSector">fragment/target_sector_fr.xdp</Fragment>


    <MasterTemplate xml:lang="en">master/default_en.xdp</MasterTemplate>
    <MasterTemplate xml:lang="fr">master/default_fr.xdp</MasterTemplate>

</ProgramConfig>

片段/目标_扇区.xdp
片段/目标\u扇区\u fr.xdp
主/默认\u en.xdp
主/默认\u fr.xdp
特定程序可以覆盖默认配置,例如:

<ProgramConfig>

    <Fragment xml:lang="en" name="TargetSector">fragment/1-5ABQ/target_sector.xdp</Fragment>

    <MasterTemplate xml:lang="fr">master/default_fr_1-5ABQ.xdp</MasterTemplate>

</ProgramConfig>

片段/1-5ABQ/target_sector.xdp
主/默认\u fr\u 1-5ABQ.xdp
我需要合并XML文档,以便输出为:

<ProgramConfig>

    <Fragment xml:lang="en" name="TargetSector">fragment/1-5ABQ/target_sector.xdp</Fragment>
    <Fragment xml:lang="fr" name="TargetSector">fragment/target_sector_fr.xdp</Fragment>


    <MasterTemplate xml:lang="en">master/default_en.xdp</MasterTemplate>
    <MasterTemplate xml:lang="fr">master/default_fr_1-5ABQ.xdp</MasterTemplate>

</ProgramConfig>

片段/1-5ABQ/target_sector.xdp
片段/目标\u扇区\u fr.xdp
主/默认\u en.xdp
主/默认\u fr\u 1-5ABQ.xdp
如果特定于程序的XML具有与默认XML相同名称和匹配属性的元素,那么它应该替换输出文档中的值

XML非常简单——它总是ProgramConfig根目录下的一组元素,没有其他子元素。每个元素定义资源的文件系统路径


有没有一种方法可以使用XSLT实现这一点。我尝试使用document函数,但我不确定如何匹配元素和所有属性。

使用XSLT 3.0,您可以为每个组使用
,并使用节点名和所有属性的组合分组键来解决此问题:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:output indent="yes"/>

    <xsl:template name="xsl:initial-template">
        <ProgramConfig>
            <xsl:for-each-group select="doc('defaultConfig.xml')/ProgramConfig/*,
                                        doc('overrideConfig.xml')/ProgramConfig/*"
                                        group-by="node-name(.), sort(@*, function($a) { name($a) })" composite="yes">
                <xsl:copy-of select="if (current-group()[2]) then current-group()[2] else current-group()[1]"/>
            </xsl:for-each-group>
        </ProgramConfig>
    </xsl:template>

</xsl:stylesheet>

使用XSLT 2.0,基于名称和所有属性值构造单个分组键要困难一些:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs math mf"
    version="2.0">

    <xsl:output indent="yes"/>

    <xsl:function name="mf:sort" as="node()*">
        <xsl:param name="input-nodes" as="node()*"/>
        <xsl:perform-sort select="$input-nodes">
            <xsl:sort select="name()"/>
        </xsl:perform-sort>
    </xsl:function>

    <xsl:template name="main">
        <ProgramConfig>
            <xsl:for-each-group select="doc('defaultConfig.xml')/ProgramConfig/*,
                doc('overrideConfig.xml')/ProgramConfig/*"
                group-by="string-join((string(node-name(.)), mf:sort(@*)), '|')">
                <xsl:copy-of select="if (current-group()[2]) then current-group()[2] else current-group()[1]"/>
            </xsl:for-each-group>
        </ProgramConfig>
    </xsl:template>

</xsl:stylesheet>

太棒了。非常感谢。一个问题-
node()*
as
属性是什么意思?我不确定它是如何匹配属性的,我认为它只会匹配元素。根据
as
属性中使用的序列类型,“任意类型测试”
node()
意味着任何类型的节点和属性都是数据模型中的节点。它与XSLT模式不同,XSLT模式定义“
node()
匹配除属性节点、名称空间节点或文档节点以外的任何节点”。