基于元素ID合并XML文件的子节点

时间:2013-04-19 03:12:03

标签: xml xslt merge

我正在尝试根据元素ID合并XML文件的子节点。例如,我有以下XML:

<category:category.fixedChildProducts>
    <category:product repositoryId="PROD-001">
        <category:product.id>PROD-001</category:product.id>
        <category:product.childSKUs>
            <category:footwear-sku repositoryId="SKU-001">
                <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-002">
                <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
        </category:product.childSKUs>
    </category:product>
    <category:product repositoryId="PROD-001">
        <category:product.id>PROD-001</category:product.id>
        <category:product.childSKUs>
            <category:footwear-sku repositoryId="SKU-003">
                <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-004">
                <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
        </category:product.childSKUs>
    </category:product>     
</category:category.fixedChildProducts>

我需要将其转换为:

<category:category.fixedChildProducts>
    <category:product repositoryId="PROD-001">
        <category:product.id>PROD-001</category:product.id>
        <category:product.childSKUs>
            <category:footwear-sku repositoryId="SKU-001">
                <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-002">
                <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-003">
                <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-004">
                <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
            </category:footwear-sku>                
        </category:product.childSKUs>
    </category:product> 
</category:category.fixedChildProducts>

基本上,我需要遍历产品的repositoryId属性,并将具有相同产品childSKUs的所有repositoryId组合在一起。每个产品节点都应具有唯一的repositoryId。请帮忙。

1 个答案:

答案 0 :(得分:0)

这是使用XSL密钥的XSLT 1.0兼容解决方案:

样式表

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:category="my:category">

  <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!-- Collect <category:product> elements into a key -->
  <xsl:key name="kProduct" match="category:product" use="@repositoryId"/>

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

  <!--
  Match the first <category:product> element with a certain @repositoryId
  attribute value in the key.

  See http://www.jenitennison.com/xslt/grouping/muenchian.html
  -->
  <xsl:template
    match="category:product[generate-id() = 
                             generate-id(key('kProduct', @repositoryId)[1])]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Drop duplicate <category:product> elements -->
  <xsl:template match="category:product"/>

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

      <!--
      Apply the <category:footwear-sku> descendants of elements in the
      'kProduct' key other than the first one, which are already applied
      in the template above
      -->
      <xsl:apply-templates
        select="key('kProduct', ../@repositoryId)
                  [position() &gt; 1]/*/category:footwear-sku"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

输入

<category:category.fixedChildProducts xmlns:category="my:category">
    <category:product repositoryId="PROD-001">
        <category:product.id>PROD-001</category:product.id>
        <category:product.childSKUs>
            <category:footwear-sku repositoryId="SKU-001">
                <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-002">
                <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
        </category:product.childSKUs>
    </category:product>
    <category:product repositoryId="PROD-001">
        <category:product.id>PROD-001</category:product.id>
        <category:product.childSKUs>
            <category:footwear-sku repositoryId="SKU-003">
                <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
            <category:footwear-sku repositoryId="SKU-004">
                <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
                <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
            </category:footwear-sku>
        </category:product.childSKUs>
    </category:product>
</category:category.fixedChildProducts>

输出

<?xml version="1.0" encoding="utf-8"?>
<category:category.fixedChildProducts xmlns:category="my:category">
  <category:product repositoryId="PROD-001">
    <category:product.id>PROD-001</category:product.id>
    <category:product.childSKUs>
      <category:footwear-sku repositoryId="SKU-001">
        <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
        <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
      </category:footwear-sku>
      <category:footwear-sku repositoryId="SKU-002">
        <category:footwear-sku.colorDefault>Black</category:footwear-sku.colorDefault>
        <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
      </category:footwear-sku>
      <category:footwear-sku repositoryId="SKU-003">
        <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
        <category:footwear-sku.sizeDefault>Large</category:footwear-sku.sizeDefault>
      </category:footwear-sku>
      <category:footwear-sku repositoryId="SKU-004">
        <category:footwear-sku.colorDefault>Red</category:footwear-sku.colorDefault>
        <category:footwear-sku.sizeDefault>Small</category:footwear-sku.sizeDefault>
      </category:footwear-sku>
    </category:product.childSKUs>
  </category:product>
</category:category.fixedChildProducts>