连接XML

时间:2010-02-08 14:56:48

标签: xml xslt exslt

我有三个xml文件

<step>
<Products>
    <Product UserTypeID="Country">
        <Name>Cyprus</Name>
        <Product UserTypeID="Resort">
            <Name>Argaka</Name>
            <Product UserTypeID="Property">
                <Name>Villa Tester</Name>
            </Product>
        </Product>
        <Product UserTypeID="Resort">
            <Name>Coral Bay</Name>
            <Product UserTypeID="Property">
                <Name>1</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>2</Name>
            </Product>
        </Product>
    </Product>
    <Product UserTypeID="Country">
        <Name>Greece</Name>
        <Product UserTypeID="Region">
            <Name>Corfu</Name>
            <Product UserTypeID="Resort">
                <Name>Aghios Stefanos</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Joanna</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa Eleonas</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Kassiopi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa 2</Name>
                </Product>
            </Product>
        </Product>
    </Product>
</Products>

<step>
<Products>
    <Product UserTypeID="Country">
        <Name>Cyprus</Name>
        <Product UserTypeID="Resort">
            <Name>Argaka</Name>
            <Product UserTypeID="Property">
                <Name>Villa Jaime</Name>
            </Product>
        </Product>
    </Product>
    <Product UserTypeID="Country">
        <Name>Greece</Name>
        <Product UserTypeID="Region">
            <Name>Corfu</Name>
            <Product UserTypeID="Resort">
                <Name>Acharavi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa 1</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa 2</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Gouvia</Name>
                <Product UserTypeID="Property">
                    <Name>Villa De Bono</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Kassiopi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa 1</Name>
                </Product>
            </Product>
        </Product>
    </Product>
</Products>

<step>
<Products>
    <Product UserTypeID="Country">
        <Name>Cyprus</Name>
        <Product UserTypeID="Resort">
            <Name>Aghia Marina</Name>
            <Product UserTypeID="Property">
                <Name>Villa Aghia Marina</Name>
            </Product>
        </Product>
        <Product UserTypeID="Resort">
            <Name>Coral Bay</Name>
            <Product UserTypeID="Property">
                <Name>Ascos Coral Villas</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>Coral Villa</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>Lella Villas</Name>
            </Product>
        </Product>
    </Product>
    <Product UserTypeID="Country">
        <Name>Greece</Name>
        <Product UserTypeID="Region">
            <Name>Corfu</Name>
            <Product UserTypeID="Resort">
                <Name>Acharavi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Angelos</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa Eleonas</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Aghios Stefanos</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Joanna</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa Eleonas</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Kassiopi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Imerolia</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Test Property</Name>
                </Product>
            </Product>
        </Product>
    </Product>
</Products>

每个文件都有相同的产品(通过./name),但有不同的子产品(通过./name),我需要将它们连接成一个树,每个产品/名称有一个产品,包含所有子产品规则,以便我可以输出一个结构。

我找到了一个xslt方法,它将创建一个如下节点集

    <xsl:variable name="step-output">
    <xsl:for-each select="/index/file">
        <xsl:copy-of select="document(.)" />
    </xsl:for-each>
</xsl:variable>
<xsl:variable name="step-products" select="exsl:node-set($step-output)//Products" />

但是,当我创建其他模板时,将按产品/名称创建三个产品,即塞浦路斯将出现三次。

有谁知道我该怎么办?我的结果需要如下

<step>
<Products>
    <Product UserTypeID="Country">
        <Name>Cyprus</Name>
        <Product UserTypeID="Resort">
            <Name>Aghia Marina</Name>
            <Product UserTypeID="Property">
                <Name>Villa Aghia Marina</Name>
            </Product>
        </Product>
        <Product UserTypeID="Resort">
            <Name>Argaka</Name>
            <Product UserTypeID="Property">
                <Name>Villa Jaime</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>Villa Tester</Name>
            </Product>
        </Product>
        <Product UserTypeID="Resort">
            <Name>Coral Bay</Name>
            <Product UserTypeID="Property">
                <Name>Ascos Coral Villas</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>Coral Villa</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>Lella Villas</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>1</Name>
            </Product>
            <Product UserTypeID="Property">
                <Name>2</Name>
            </Product>
        </Product>
    </Product>
    <Product UserTypeID="Country">
        <Name>Greece</Name>
        <Product UserTypeID="Region">
            <Name>Corfu</Name>
            <Product UserTypeID="Resort">
                <Name>Acharavi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Angelos</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa Eleonas</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa 1</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa 2</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Aghios Stefanos</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Joanna</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa Eleonas</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Gouvia</Name>
                <Product UserTypeID="Property">
                    <Name>Villa De Bono</Name>
                </Product>
            </Product>
            <Product UserTypeID="Resort">
                <Name>Kassiopi</Name>
                <Product UserTypeID="Property">
                    <Name>Villa Imerolia</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Test Property</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa 1</Name>
                </Product>
                <Product UserTypeID="Property">
                    <Name>Villa 2</Name>
                </Product>
            </Product>
        </Product>
    </Product>
</Products>

2 个答案:

答案 0 :(得分:4)

这是一个应该完成工作的XSLT 2.0样式表:

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

  <xsl:output indent="yes"/>

  <xsl:template match="/">
    <step>
      <Products>
        <xsl:for-each-group select="document(index/file)/step/Products/Product" group-by="Name">
          <Product UserTypeID="{@UserTypeID}">
            <Name><xsl:value-of select="current-grouping-key()"/></Name>
            <xsl:for-each-group select="current-group()/Product" group-by="Name">
              <xsl:sort select="current-grouping-key()"/>
              <Product UserTypeID="{@UserTypeID}">
                <Name><xsl:value-of select="current-grouping-key()"/></Name>
                <xsl:for-each select="current-group()/Product">
                  <xsl:sort select="Name"/>
                  <xsl:copy-of select="."/>
                </xsl:for-each>
              </Product>
            </xsl:for-each-group>
          </Product>
        </xsl:for-each-group>
      </Products>
    </step>
  </xsl:template>

</xsl:stylesheet>

您需要针对具有结构

的索引XML文档运行它
<index>
  <file>test2010020803.xml</file>
  <file>test2010020804.xml</file>
  <file>test2010020805.xml</file>
</index>

列出了您要处理的其他文件。

XSLT 2.0样式表可以使用Saxon 9执行,它带有.NET和Java版本,因此它可以运行至少Java 1.5或.NET 2.0可用或可以安装的任何地方。其他选项包括AltovaXML tools(仅限Windows)和Gestalt

如果您绑定到XSLT 1.0,那么只要您有exsl:node-set或类似支持,就可以按照以下方式执行:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  exclude-result-prefixes="exsl"
  version="1.0">

  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="k1" match="step/Products/Product" use="Name"/>
  <xsl:key name="k2" match="step/Products/Product/Product" use="concat(../Name, '|', Name)"/>

  <xsl:template match="/">
    <xsl:variable name="rtf">
      <xsl:copy-of select="document(index/file)/*"/>
    </xsl:variable>
    <step>
      <Products>
        <xsl:for-each select="exsl:node-set($rtf)/step/Products/Product[generate-id() = generate-id(key('k1', Name)[1])]">
          <Product UserTypeID="{@UserTypeID}">
            <xsl:copy-of select="Name"/>
            <xsl:for-each select="key('k1', Name)/Product[generate-id() = generate-id(key('k2', concat(../Name, '|', Name))[1])]">
              <xsl:sort select="Name"/>
              <Product UserTypeID="{@UserTypeID}">
                <xsl:copy-of select="Name"/>
                <xsl:for-each select="key('k2', concat(../Name, '|', Name))/Product">
                  <xsl:sort select="Name"/>
                  <xsl:copy-of select="."/>
                </xsl:for-each>
              </Product>
            </xsl:for-each>
          </Product>
        </xsl:for-each>
      </Products>
    </step>
  </xsl:template>

</xsl:stylesheet>

键看起来像这样:

  <xsl:key name="k1" match="step/Products/Product" use="Name"/>

  <xsl:key name="k2" match="step/Products/Product/Product" use="concat(../Name, '|', Name)"/>

  <xsl:key name="k3" match="step/Products/Product/Product/Product"
                     use="concat(../../Name, '|', ../Name, '|', Name)"/>

  <xsl:key name="k4" 
           match="step/Products/Product/Product/Product/Product"
           use="concat(../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/>

  <xsl:key name="k5" 
           match="step/Products/Product/Product/Product/Product/Product"
           use="concat(../../../../Name, '|', ../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/>

  <xsl:key name="k6" 
           match="step/Products/Product/Product/Product/Product/Product/Product"
           use="concat(../../../../../Name, '|', ../../../../Name, '|', ../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/>

这一切都直接在论坛编辑器中输入,因此可能有错误。

答案 1 :(得分:0)

编辑文本以创建文件将起作用,但可能难以维护。

最简单的方法是将所有3个文件的XML解析为对象形式。以编程方式在单个父节点下添加对象,然后重新生成新的XML文件。

您的环境是否可以将此作为可接受的解决方案?