3

我想做从 XML 到结合一些元素的文本的转换,但要避免输出中的重复。XML 会是这样的:

<A>
  <B>
    <param1>value0</param1>
    <param2>value1</param2>
  </B>
  <B>
    <param1>value2</param1>
    <param2>value3</param2>
  </B>
  <C>
    <param3>valueC1</param3>
    <D>
      <param4>value0</param4>
      <param5>value4</param5>
    </D>
    <D>
      <param4>value0</param4>
      <param5>value5</param5>
    </D>
    <D>
      <param4>value2</param4>
      <param5>value6</param5>
    </D>
  </C>
  <C>
    <param3>valueC2</param3>
    <D>
      <param4>value0</param4>
      <param5>value5</param5>
    </D>
  </C>
</A>

和输出:

OBJECT: param1=value0, param2=value1, param3=valueC1, param4=value0;
OBJECT: param1=value2, param2=value3, param3=valueC1, param4=value2;
OBJECT: param1=value0, param2=value1, param3=valueC2, param4=value0;

笔记:

  • 对于每个 D 对象,使用 D.param4 = B.param1 查找与 B 对象的匹配项
  • 如果有两个或多个 D 对象进入同一个 C 并与同一个 B 匹配,则只打印其中一个(在示例中,对第二个 D 对象不做任何事情,因为它会产生与第一个对象相同的行)
  • 如果有两个 D 对象与相同的 B 匹配,但在不同的 C 中,则打印两者(输出示例中的第三行)

我寻找了一些类似的问题,但在同一案例中找不到任何问题。

我想这可以通过使用键来完成,但它太复杂了。

谢谢!

问候,艾尔。

PS:对不起我的英语。

4

2 回答 2

3

鉴于您没有param5在输出中使用任何内容,似乎可以将问题简化为

  • 对于每个 C
    • 找到与任何包含的 D匹配的所有不同的B 元素param1param4
    • 对于每一个
      • 再次提取 B/param1、B/param2、currentC/param3、B/param1(但标记为 param4)

这是使用模板实现这一目标的一种方法。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" />
  <xsl:key name="BbyParam1" match="B" use="param1" />

  <xsl:template match="/">
    <xsl:apply-templates select="A/C" />
  </xsl:template>

  <xsl:template match="C">
    <xsl:apply-templates select="key('BbyParam1', D/param4)">
      <xsl:with-param name="currentC" select="." />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="B">
    <xsl:param name="currentC" />
    <xsl:text>OBJECT: param1=</xsl:text>
    <xsl:value-of select="param1" />
    <xsl:text>, param2=</xsl:text>
    <xsl:value-of select="param2" />
    <xsl:text>, param3=</xsl:text>
    <xsl:value-of select="$currentC/param3" />
    <xsl:text>, param4=</xsl:text>
    <xsl:value-of select="param1" />
    <xsl:text>&#10;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

“找到与任何包含的 D匹配的所有不同的B 元素”实际上非常简单,因为当您将节点集作为第二个参数传递给函数时,它正是这样做的 - 它返回所有节点的集合其键值是参数节点集中任何节点的字符串值,并且返回的节点集(作为一个集合)保证不包含重复项。param1param4key

于 2013-02-13T11:25:52.883 回答
0

这应该可以解决问题:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="yes"/>
  <xsl:key name="kB" match="B" use="param1" />
  <xsl:key name="kD" match="D" 
           use="concat(param4, '+', generate-id(..))"/>

  <xsl:template match="/">
    <xsl:apply-templates select="A/C" />
  </xsl:template>

  <xsl:template match="C">
    <xsl:apply-templates select="D[key('kB', param4) and 
                                    generate-id() = 
                                    generate-id(key('kD', 
                                       concat(
                                          param4, 
                                          '+', 
                                          generate-id(..)
                                       )
                                    )[1])]" />
  </xsl:template>

  <xsl:template match="D">
    <xsl:value-of 
      select="concat('OBJECT: param1=', 
                     key('kB', param4)/param1, 
                     ', param2=', 
                     key('kB', param4)/param2,
                     ', param3=',
                     ../param3,
                     ', param4=',
                     param4,
                     '&#xA;')"/>
  </xsl:template>
</xsl:stylesheet>

在您的样本上运行时的输出:

OBJECT: param1=value0, param2=value1, param3=valueC1, param4=value0
OBJECT: param1=value2, param2=value3, param3=valueC1, param4=value2
OBJECT: param1=value0, param2=value1, param3=valueC2, param4=value0
于 2013-02-13T11:39:09.070 回答