本文介绍了使用XSLT合并具有相同同级的2个XML文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个XML文件(XML1和XML2:粘贴在下面),需要将从XML2到XML1的更改合并到第三个文件(例如XML3)中,这样:

I have two XML files (XML1 and XML2: pasted below) and need to merge changes from XML2 to XML1 in to third file (say XML3) such that:

1)如果在两个文件中都找到相同的属性,则 1.a)检查属性值是否不同,然后用XML2中的值覆盖XML1中的值.例如MasterControl在XML1中启用,而在XML2中禁用.合并后,预期输出为XML3中为禁用"的MasterControl.

1) If same attribute found in both files then 1.a) Check if attibute values are different then overwrite value of XML1 with value from XML2. e.g. MasterControl is Enabled in XML1 while Disabled in XML2. After merge, expected output is MasterControl as Disabled in XML3.

1.b)如果两个文件中的属性值相同或为空,则合并到XML3中后XML1不变.

1.b) If attribute values are same or empty in both file then no change in XML1 after merging in XML3.

2)如果XML 1具有XML2中不存在的额外属性,则在合并文件中添加此类属性.

2) If XML 1 has extra attributes which are not present in XML2 then add such attributes in merged file.

3)如果XML 2具有XML1中不存在的额外属性,则在合并文件中添加此类属性.

3) If XML 2 has extra attributes which are not present in XML1 then add such attributes in merged file.

我已将链接"XSLT合并2 XML文件" XSLT合并2 XML文件,它满足了大多数要求,但以下各项除外:

I have reffered link "XSLT to Merge 2 XML Files" XSLT to Merge 2 XML Files, which solved most of the requirement excepts following:

合并后,我在规则ID树中遇到了问题,其中所有规则ID的层次结构路径都相同.在上面提到的链接中,将为每个元素计算路径并基于该路径进行合并.

After merging, i have faced issue in Rule ID tree where hierachy path is same for all Rule IDs. In above mentioned link, path is calculated for each element and based on it, merging done.

我正在寻找通用解决方案,因为这只是XML文件的一小段.文件中大约有300多个参数.XML:1

I am searching for generic solution because this is just small snippet of XML file. there are approx 300+ parameters in the files.XML:1

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="D:\test.xsl"?>
<NCP>
        <NCPList>
            <NCP ID="1" Label="LabelName">
                <ParametersList>
                <MasterControl>Enabled</MasterControl>              
                <ReservedPool></ReservedPool>               
                <Rule ID="1" Label="Label">
                    <RuleCriteria>
                        <CellType>Macro</CellType>
                    </RuleCriteria>                 
                    <Assignment>Enabled</Assignment>
                    <ReAssignment>Enabled</ReAssignment>                    
                </Rule> 

                <Rule ID="2" Label="Label">
                    <RuleCriteria>
                        <CellType>Micro</CellType>
                    </RuleCriteria>                 
                    <Assignment>Enabled</Assignment>
                    <ReAssignment>Disabled</ReAssignment>                   
                </Rule>

                <Rule ID="3" Label="Label">
                    <RuleCriteria>
                        <CellType>Pico</CellType>
                    </RuleCriteria>                 
                    <Assignment>Enabled</Assignment>
                    <ReAssignment>Disabled</ReAssignment>                   
                </Rule>             
            </ParametersList>
            </NCP>
        </NCPList>
    </NCP>

XMl2:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="D:\test.xsl"?>
<NCP>
        <NCPList>
            <NCP ID="1" Label="LabelName">
                <ParametersList>
                <MasterControl>Disabled</MasterControl>             
                <ReservedPool></ReservedPool>               
                <Rule ID="1" Label="Label">
                    <RuleCriteria>
                        <CellType>Macro</CellType>
                    </RuleCriteria>                 
                    <Assignment>Disabled</Assignment>
                    <ReAssignment>Disabled</ReAssignment>                   
                </Rule> 

                <Rule ID="2" Label="Label">
                    <RuleCriteria>
                        <CellType>Micro</CellType>
                    </RuleCriteria>                 
                    <Assignment>Enabled</Assignment>
                    <ReAssignment>Disabled</ReAssignment>                   
                </Rule>

            </ParametersList>
            </NCP>
        </NCPList>
    </NCP>

XSLT:

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

  <xsl:param name="aXmlPath" select="''" />
  <xsl:param name="aDoc"     select="document('q_xml2.xml')" />

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

  <!-- text nodes will be checked against doc A -->
  <xsl:template match="*[not(*)]/text()">
    <xsl:variable name="path">
      <xsl:call-template name="calculatePath" />
    </xsl:variable>

    <xsl:variable name="valueFromA">
      <xsl:call-template name="nodeValueByPath">
        <xsl:with-param name="path"    select="$path" />
        <xsl:with-param name="context" select="$aDoc" />
      </xsl:call-template>
    </xsl:variable>

    <xsl:choose>
      <!-- either there is something at that path in doc A -->
      <xsl:when test="starts-with($valueFromA, 'found:')">
        <!-- remove prefix added in nodeValueByPath, see there --> 
        <xsl:value-of select="substring-after($valueFromA, 'found:')" />
      </xsl:when>
      <!-- or we take the value from doc B -->
      <xsl:otherwise>
        <xsl:value-of select="." />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- this calcluates a simpe path for a node -->
  <xsl:template name="calculatePath">
    <xsl:for-each select=".."> 
      <xsl:call-template name="calculatePath" />
    </xsl:for-each>

    <xsl:if test="self::*">     
      <xsl:value-of select="concat(name(), '/')" />
    </xsl:if>
  </xsl:template>

  <!-- this retrieves a node value by its simple path -->
  <xsl:template name="nodeValueByPath">
    <xsl:param name="path"    select="''" />
    <xsl:param name="context" select="''" />

    <xsl:if test="contains($path, '/') and count($context)">
      <xsl:variable name="elemName" select="substring-before($path, '/')" />
      <xsl:variable name="nextPath" select="substring-after($path, '/')" />
      <xsl:variable name="currContext" select="$context/*[name() = $elemName][1]" />

      <xsl:if test="$currContext">
        <xsl:choose>
          <xsl:when test="contains($nextPath, '/')">
            <xsl:call-template name="nodeValueByPath">
              <xsl:with-param name="path"    select="$nextPath" />
              <xsl:with-param name="context" select="$currContext" />
            </xsl:call-template>
          </xsl:when>
          <xsl:when test="not($currContext/*)">
            <!-- always add a prefix so we can detect 
                 the case "exists in A, but is empty" -->
            <xsl:value-of select="concat('found:', $currContext/text())" />
          </xsl:when>
        </xsl:choose>
      </xsl:if>
    </xsl:if>    
  </xsl:template>
</xsl:stylesheet>

实际输出:

 <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="D:\test.xsl"?>
<NCP>
            <NCPList>
                <NCP ID="1" Label="LabelName">
                    <ParametersList>
                    <MasterControl>Disabled</MasterControl>             
                    <ReservedPool/>             
                    <Rule ID="1" Label="Label">
                        <RuleCriteria>
                            <CellType>Macro</CellType>
                        </RuleCriteria>                 
                        <Assignment>Disabled</Assignment>
                        <ReAssignment>Disabled</ReAssignment>                   
                    </Rule> 

                    <Rule ID="2" Label="Label">
                        <RuleCriteria>
                            <CellType>Macro</CellType>
                        </RuleCriteria>                 
                        <Assignment>Disabled</Assignment>
                        <ReAssignment>Disabled</ReAssignment>                   
                    </Rule>

                    <Rule ID="3" Label="Label">
                        <RuleCriteria>
                            <CellType>Macro</CellType>
                        </RuleCriteria>                 
                        <Assignment>Disabled</Assignment>
                        <ReAssignment>Disabled</ReAssignment>                   
                    </Rule>             
                </ParametersList>
                </NCP>
            </NCPList>
        </NCP>

请参见上面的ReservedPool属性终止而没有结束标记.同样,所有规则ID都与同一单元格类型树合并,而两个xml的每个规则ID都有不同的单元格类型.

see above ReservedPool attribute terminated without ending tag.Also all Rule IDs merged with same CellType tree while both xmls have different CellType for each Rule Id .

预期输出:

 <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="D:\test.xsl"?>
<NCP>
            <NCPList>
                <NCP ID="1" Label="LabelName">
                    <ParametersList>
                    <MasterControl>Disabled</MasterControl>             
                    <ReservedPool></ReservedPool>               
                    <Rule ID="1" Label="Label">
                        <RuleCriteria>
                            <CellType>Macro</CellType>
                        </RuleCriteria>                 
                        <Assignment>Disabled</Assignment>
                        <ReAssignment>Disabled</ReAssignment>                   
                    </Rule> 

                    <Rule ID="2" Label="Label">
                        <RuleCriteria>
                            <CellType>Micro</CellType>
                        </RuleCriteria>                 
                        <Assignment>Enabled</Assignment>
                        <ReAssignment>Disabled</ReAssignment>                   
                    </Rule>

                    <Rule ID="3" Label="Label">
                        <RuleCriteria>
                            <CellType>Pico</CellType>
                        </RuleCriteria>                 
                        <Assignment>Enabled</Assignment>
                        <ReAssignment>Disabled</ReAssignment>                   
                    </Rule>             
                </ParametersList>
                </NCP>
            </NCPList>
        </NCP>

请为以上疑问提供帮助.

Please provide help in above doubts.

预先感谢

推荐答案

根据您的澄清进行了

Edited in response to your clarifications:

我相信您的要求可以凝结为:

I believe your requirements could be condensed to:

  1. 从XML1中获取所有具有相应参数的参数(覆盖)XML2中的参数;

  1. Take all parameters from XML1 that do not have a corresponding(overriding) parameter in XML2;

从XML2中获取所有参数(这些参数覆盖了XML1中存在的参数,或不存在的其他参数出现在XML1中.)

Take all parameters from XML2 (these are either overriding aparameter that exists in XML1, or extra parameters which are notpresent in XML1).

进一步的复杂之处在于,Rules需要与它们的CellType匹配,而其他参数(MasterControlReservedPool)要与它们的名称匹配.

There's a further complication in that Rules need to be matched by their CellType, while other parameters (MasterControl and ReservedPool) by their name.

考虑到这一点,请尝试:

With that in mind, try:

XSLT 1.0

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="doc2" select="document('q_xml2.xml')" />

<xsl:variable name="doc2-param-names">
    <xsl:for-each select="$doc2/NCP/NCPList/NCP/ParametersList/*">
        <name><xsl:value-of select="name()"/></name>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="doc2-cell-types" select="$doc2/NCP/NCPList/NCP/ParametersList/Rule/RuleCriteria/CellType" />

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

<xsl:template match="ParametersList"> 
    <xsl:copy>
        <!-- local parameters (other than Rules), with no external override -->
        <xsl:apply-templates select="*[not(self::Rule)] [not(name()=exsl:node-set($doc2-param-names)/name)]"/>
        <!-- local Rules, with no external override -->
        <xsl:apply-templates select="Rule[not(RuleCriteria/CellType=$doc2-cell-types)]"/>
        <!-- ALL external items -->
        <xsl:apply-templates select="$doc2/NCP/NCPList/NCP/ParametersList/*"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>


使用以下方法进行测试:


Testing with:

XML INPUT

<NCP>
  <NCPList>
    <NCP ID="1" Label="LabelName">
      <ParametersList>
        <MasterControl>Enabled</MasterControl>
        <ReservedPool/>
        <OLD>OLD</OLD>
        <Rule ID="1" Label="Label">
          <RuleCriteria>
            <CellType>Macro</CellType>
          </RuleCriteria>
          <Assignment>Enabled</Assignment>
          <ReAssignment>Enabled</ReAssignment>
        </Rule>
        <Rule ID="2" Label="Label">
          <RuleCriteria>
            <CellType>Micro</CellType>
          </RuleCriteria>
          <Assignment>Enabled</Assignment>
          <ReAssignment>Disabled</ReAssignment>
        </Rule>
        <Rule ID="3" Label="Label">
          <RuleCriteria>
            <CellType>Pico</CellType>
          </RuleCriteria>
          <Assignment>Enabled</Assignment>
          <ReAssignment>Disabled</ReAssignment>
        </Rule>
      </ParametersList>
    </NCP>
  </NCPList>
</NCP>

文件q_xml2.xml

<?xml version="1.0" encoding="UTF-8"?>
<NCP>
  <NCPList>
    <NCP ID="1" Label="LabelName">
      <ParametersList>
        <MasterControl>DISABLED</MasterControl>
        <ReservedPool/>
        <NEW>NEW</NEW>
        <Rule ID="1" Label="Label">
          <RuleCriteria>
            <CellType>Macro</CellType>
          </RuleCriteria>
          <Assignment>Disabled</Assignment>
          <ReAssignment>Disabled</ReAssignment>
        </Rule>
        <Rule ID="2" Label="Label">
          <RuleCriteria>
            <CellType>Micro</CellType>
          </RuleCriteria>
          <Assignment>Enabled</Assignment>
          <ReAssignment>Disabled</ReAssignment>
        </Rule>
      </ParametersList>
    </NCP>
  </NCPList>
</NCP>

结果

<?xml version="1.0" encoding="UTF-8"?>
<NCP>
   <NCPList>
      <NCP ID="1" Label="LabelName">
         <ParametersList>
            <OLD>OLD</OLD>
            <Rule ID="3" Label="Label">
               <RuleCriteria>
                  <CellType>Pico</CellType>
               </RuleCriteria>
               <Assignment>Enabled</Assignment>
               <ReAssignment>Disabled</ReAssignment>
            </Rule>
            <MasterControl>DISABLED</MasterControl>
            <ReservedPool/>
            <NEW>NEW</NEW>
            <Rule ID="1" Label="Label">
               <RuleCriteria>
                  <CellType>Macro</CellType>
               </RuleCriteria>
               <Assignment>Disabled</Assignment>
               <ReAssignment>Disabled</ReAssignment>
            </Rule>
            <Rule ID="2" Label="Label">
               <RuleCriteria>
                  <CellType>Micro</CellType>
               </RuleCriteria>
               <Assignment>Enabled</Assignment>
               <ReAssignment>Disabled</ReAssignment>
            </Rule>
         </ParametersList>
      </NCP>
   </NCPList>
</NCP>

这篇关于使用XSLT合并具有相同同级的2个XML文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-21 05:54