XSLT - 从所有子元素

时间:2016-05-11 19:35:46

标签: xslt

使用XSLT 2.0,我试图在以下文档中创建给定元素的所有子元素之间的关系列表:

<doc>
    <part1>
        <name>John</name>
        <name>Paul</name>
        <name>George</name>
        <name>Ringo</name>
        <place>Liverpool</place>
    </part1>
    <part2>
        <name>Romeo</name>
        <name>Romeo</name>
        <name>Juliet</name>
        <fam>Montague</fam>
        <fam>Capulet</fam>
    </part2>
</doc>

我想获得的结果,理想情况是通过混淆和权衡相同的关系,将是(以任何顺序)类似的东西:

<doc>
    <part1>
        <rel><name>John</name><name>Paul</name></rel>
        <rel><name>John</name><name>George</name></rel>
        <rel><name>John</name><name>Ringo</name></rel>
        <rel><name>Paul</name><name>George</name></rel>
        <rel><name>Paul</name><name>Ringo</name></rel>
        <rel><name>George</name><name>Ringo</name></rel>
        <rel><name>John</name><place>Liverpool</place></rel>
        <rel><name>Paul</name><place>Liverpool</place></rel>
        <rel><name>George</name><place>Liverpool</place></rel>
        <rel><name>Ringo</name><place>Liverpool</place></rel>
    </part1>
    <part2>
        <rel weight="2"><name>Romeo</name><name>Juliet</name></rel>
        <rel weight="2"><name>Romeo</name><fam>Montague</fam></rel>
        <rel weight="2"><name>Romeo</name><fam>Capulet</fam></rel>
        <rel><name>Juliet</name><fam>Montague</fam></rel>
        <rel><name>Juliet</name><fam>Capulet</fam></rel>
        <rel><fam>Montague</fam><fam>Capulet</fam></rel>
    </part2>
</doc>

- 但我不确定如何继续。非常感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

至少可以使用以下XSLT脚本解决问题的组合部分。它没有解决重复的问题,但可以在第二次转换中完成。

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

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

  <xsl:template match="doc/*">
    <xsl:copy>
      <xsl:variable name="l" select="./*"/>
      <xsl:for-each select="$l">
        <xsl:variable name="a" select="."/>
        <xsl:variable name="posa" select="position()"/>
        <xsl:variable name="namea" select="name()"/>
        <xsl:for-each select="$l">
          <xsl:if test="position() > $posa and (. != $a or name() != $namea)">
            <rel>
              <xsl:copy-of select="$a"/>
              <xsl:copy-of select="."/>
            </rel>
          </xsl:if>
        </xsl:for-each>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

当应用于示例的第一部分时,会产生:

<part1>
  <rel><name>John</name><name>Paul</name></rel>
  <rel><name>John</name><name>George</name></rel>
  <rel><name>John</name><name>Ringo</name></rel>
  <rel><name>John</name><place>Liverpool</place></rel>
  <rel><name>Paul</name><name>George</name></rel>
  <rel><name>Paul</name><name>Ringo</name></rel>
  <rel><name>Paul</name><place>Liverpool</place></rel>
  <rel><name>George</name><name>Ringo</name></rel>
  <rel><name>George</name><place>Liverpool</place></rel>
  <rel><name>Ringo</name><place>Liverpool</place></rel>
</part1>

这似乎是正确的。如果不知道是否可以在同一转换中完成重复消除(或称为加权)。

答案 1 :(得分:0)

你还没有解释这里需要应用的逻辑,所以这很大程度上是基于猜测:

XSLT 2.0

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

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

<xsl:template match="doc/*">
    <!-- first pass-->
    <xsl:variable name="unique-items">
        <xsl:for-each-group select="*" group-by="concat(name(), '|', .)">
            <item name="{name()}" count="{count(current-group())}" value="{.}"/>
        </xsl:for-each-group>
    </xsl:variable>
    <!-- output -->
    <xsl:copy>
        <xsl:for-each select="$unique-items/item">
            <xsl:variable name="left" select="."/>
            <xsl:for-each select="following-sibling::item">
                <xsl:variable name="weight" select="$left/@count * @count" />
                <rel>
                    <xsl:if test="$weight gt 1">
                        <xsl:attribute name="weight" select="$weight"/>
                    </xsl:if>
                    <xsl:apply-templates select="$left | ." />
                </rel>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

<xsl:template match="item">
    <xsl:element name="{@name}">
        <xsl:value-of select="@value"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

这里的想法是在第一遍中删除重复项,然后在第二遍(最终)传递中枚举所有组合。权重的计算方法是将组合对中每个成员的出现次数相乘,并仅在超过1时显示。