使用python合并具有相同节点的XML文件

时间:2018-10-11 05:07:58

标签: python xml xslt merge salesforce

试图合并以下XML。我想在Python中做到这一点,尽管无论如何都不是必需的。

文件1:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types> 
        <members>Class 1</members> 
        <members>Class 2</members>    
        <name>ApexClass</name>
    </types>
    <types>
        <members>Trigger 1</members>
        <name>ApexTrigger</name>
    </types>
    <types>
        <members>Rule 1</members>
        <members>Rule 2</members>
        <name>WorkflowRule</name>
    </types>   
    <types>
        <members>Address</members>
        <name>CustomField</name>
    </types>     
    <version>39.0</version>
</Package>

文件2:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Class 3</members>  
        <name>ApexClass</name>
    </types>
    <types>
        <members>Rule 2</members>
        <name>WorkflowRule</name>
    </types>  
    <types>
        <members>Phone</members>
        <name>CustomField</name>
    </types>     
    <version>41.0</version>
</Package>

合并文件1 文件2 在下面创建文件3

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Class 1</members> 
        <members>Class 2</members>    
        <members>Class 3</members>    
        <name>ApexClass</name>
    </types>
    <types>
        <members>Trigger 1</members>
        <name>ApexTrigger</name>
    </types>
    <types>
        <members>Rule 1</members>
        <members>Rule 2</members>
        <name>WorkflowRule</name>
    </types>  
    <types>
        <members>Address</members>
        <members>Phone</members>
        <name>CustomField</name>
    </types>     
    <version>41.0</version>
</Package>

请注意,标识节点可以是50多个不同值之一。

在此先感谢您的帮助。

编辑:糟糕,否决票很痛。为了澄清和证明这个问题,我应该指出,由于对SO的广泛搜索没有任何线索,因此我很难确定从哪里开始这个问题,并且问题的重点是从何处开始获得建议

1 个答案:

答案 0 :(得分:1)

由于您已准备好考虑使用Python编码的替代方法,因此这里提供了XSLT 3.0解决方案:

<xsl:transform version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    xpath-default-namespace="http://soap.sforce.com/2006/04/metadata"
    expand-text="true">
    <xsl:param name="file1" as="xs:string"/>
    <xsl:param name="file2" as="xs:string"/>
    <xsl:template name="xsl:initial-template">
        <Package xmlns="http://soap.sforce.com/2006/04/metadata">
            <xsl:merge>
                <xsl:merge-source for-each-source="$file1, $file2"
                    select="//types" sort-before-merge="true">
                    <xsl:merge-key select="name"/>
                </xsl:merge-source>
                <xsl:merge-action>
                    <types>
                        <xsl:for-each-group select="current-merge-group()/members"
                            group-by=".">
                            <xsl:copy-of select="current-group()[1]"/>
                        </xsl:for-each-group>
                        <name>{current-merge-key()}</name>
                    </types>
                </xsl:merge-action>
            </xsl:merge>
        </Package>
    </xsl:template>
</xsl:transform>

您可以从命令行按如下所示运行它:

java net.sf.saxon.Transform -xsl:test.xsl -t -it file1=file1.xml file2=file2.xml !indent=yes

说明:xsl:merge-source标识要合并的元素的两个序列; xsl:merge-key定义了要在其上进行合并的键,并告诉我们该键尚未对序列进行排序。 xsl:merge-action表示如何处理共享合并键的每组元素;在这种情况下,我们使用<members>输出不同的xsl:for-each-group元素,然后输出<name>

输出与所需输出之间有一个区别:样式表生成按<name>排序的输出。我不确定您对输出进行排序的标准;如果输出顺序很重要,那么我们可能需要进行调整。