【问题标题】:xsltproc merging xml files not workingxsltproc合并xml文件不起作用
【发布时间】:2018-05-21 09:17:34
【问题描述】:

您好,我必须在以下条件下合并 xml 文件:

复制新文件的所有现有节点,然后与旧文件值合并。 例如:

文件 abc.xml

<?xml version="1.0"?>
<schedule>
    <Item Id="2">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="9">
        <measurements>
            <measurement>Gamma</measurement>
        </measurements>
    </Item>
</schedule>

文件 xyz.xml

<?xml version="1.0"?>
<schedule>
    <Item Id="1">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="4">
        <measurements>
            <measurement>Beta</measurement>
        </measurements>
    </Item>
</schedule>

xslt 逻辑文件: 逻辑.xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="no" indent="yes"/>

<xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

<xsl:template match="Item">
    <xsl:variable name="match" select="document('./abc.xml')/schedule/Item[measurements/measurement=current()/measurements/measurement]"/>
    <xsl:choose>
        <xsl:when test="$match">
            <xsl:copy-of select="$match"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

使用的命令:

xsltproc logic.xslt xyz.xml > output.xml

预期输出:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<schedule>
    <Item Id="2">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="4">
        <measurements>
            <measurement>Beta</measurement>
        </measurements>
    </Item>
    <Item Id="9">
        <measurements>
            <measurement>Gamma</measurement>
        </measurements>
    </Item>
</schedule>

但实际与预期不同,如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<schedule>
    <Item Id="2">
        <measurements>
            <measurement>Alpha</measurement>
        </measurements>
    </Item>
    <Item Id="9">
        <measurements>
            <measurement>Gamma</measurement>
        </measurements>
    </Item>
</schedule>

它错过了新 xml 文件中的节点。

【问题讨论】:

    标签: xml linux xslt merge rhel


    【解决方案1】:

    改变

    <xsl:choose>
        <xsl:when test="$match">
            <xsl:copy-of select="$match"/>
        </xsl:when>
    </xsl:choose>
    

    <xsl:choose>
        <xsl:when test="$match">
            <xsl:copy-of select="$match"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
    </xsl:choose>
    

    通过编辑问题和需要复制第二个文档中的其他元素,我认为问题更加困难,使用 XSLT 3 你可以像https://xsltfiddle.liberty-development.net/pPqsHTf 中那样做

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="3.0">
    
        <xsl:mode on-no-match="shallow-copy"/>
    
        <xsl:strip-space elements="*"/>
        <xsl:output indent="yes"/>
    
        <xsl:param name="doc1" select="/"/>
    
        <xsl:param name="doc2">
            <schedule>
                <Item Id="2">
                    <measurements>
                        <measurement>Alpha</measurement>
                    </measurements>
                </Item>
                <Item Id="9">
                    <measurements>
                        <measurement>Gamma</measurement>
                    </measurements>
                </Item>
            </schedule>      
        </xsl:param>
    
        <xsl:key name="ref" match="Item" use="measurements/measurement"/>
    
        <xsl:template match="schedule">
            <xsl:copy>
                <xsl:apply-templates select="Item, $doc2/schedule/Item[not(key('ref', measurements/measurement, $doc1))]"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Item[root() is $doc1 and key('ref', measurements/measurement, $doc2)]">
            <xsl:copy-of select="key('ref', measurements/measurement, $doc2)"/>
        </xsl:template>
    
    </xsl:stylesheet>
    

    (当然,您可以使用&lt;xsl:param name="doc2" select="document('abc.xml')"/&gt;,而不是内联第二个文档)但是使用XSLT 1,使用变量和键更加困难,并且您不能在匹配模式中使用它们,因此似乎需要一种方法如https://xsltfiddle.liberty-development.net/pPqsHTf/2

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
    
        <xsl:strip-space elements="*"/>
        <xsl:output indent="yes"/>
    
        <xsl:param name="doc1" select="/"/>
    
        <xsl:param name="doc2-rtf">
            <schedule>
                <Item Id="2">
                    <measurements>
                        <measurement>Alpha</measurement>
                    </measurements>
                </Item>
                <Item Id="9">
                    <measurements>
                        <measurement>Gamma</measurement>
                    </measurements>
                </Item>
            </schedule>      
        </xsl:param>
    
        <xsl:param name="doc2" select="exsl:node-set($doc2-rtf)" xmlns:exsl="http://exslt.org/common"/>
    
        <xsl:template match="schedule">
            <xsl:copy>
                <xsl:apply-templates select="Item"/>
                <xsl:copy-of select="$doc2/schedule/Item[not(measurements/measurement = $doc1//Item/measurements/measurement)]"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Item">
            <xsl:choose>
                <xsl:when test="measurements/measurement = $doc2//Item/measurements/measurement">
                    <xsl:copy-of select="$doc2//Item[measurements/measurement = current()/measurements/measurement]"/>              
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
    </xsl:stylesheet>
    

    当然再次简单地使用 &lt;xsl:param name="doc2" select="document('abc.xml')"/&gt; 而不是内联数据(我只是为了有一个完整的示例而这样做,不幸的是,使用 XSLT 1 然后需要使用节点集扩展函数)。

    【讨论】:

    • 感谢马丁的回复。但是使用这种逻辑,它会错过新文件中不存在的节点。例如我刚刚编辑的这种情况下的“Gamma”。
    • 那么哪个文档决定了您要与其他文档中的元素进行比较的元素?您如何确定生成的Item 元素的顺序?
    • 顺序是先复制xyz.xml中的所有Item,然后更新/合并abc.xml中的Item,这样最终的文件就包含了abc.xml和xyz.xml的所有Item。最终文件应该包含两个 xml 的所有项目,但公共项目值将被 abc.xml 覆盖实际上,这是一个软件升级场景,我们需要保留旧版本设置,将公共节点值与旧版本值合并,最后从最新版本添加新设置。
    • 那么为什么预期的输出将Gamma元素作为第二个元素呢?不应该在从主要输入中获取的元素之后添加吗?
    • @SambitMishra,我已经编辑了答案并添加了一个希望实现合并和复制的示例。
    猜你喜欢
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    相关资源
    最近更新 更多