在xslt中连接唯一的子节点

时间:2015-02-19 00:59:58

标签: xslt

我需要连接在一个父节点中具有不同节点的节点。

我的XML如下所述:

<AllEmails>
<MailObject>
<ToEmail>abc@gmail.com</ToEmail>
<CCEmail>def@gmail.com</CCEmail>
<Content>Content 1</Content>
</MailObject>
<MailObject>
<ToEmail>abc@gmail.com</ToEmail>
<CCEmail>def@gmail.com</CCEmail>
<Content>Content 2</Content>
</MailObject>
<MailObject>
<ToEmail>geh@gmail.com</ToEmail>
<CCEmail>ijk@gmail.com</CCEmail>
<Content>Content 3</Content>
</MailObject>
<MailObject>
<ToEmail>geh@gmail.com</ToEmail>
<CCEmail>ijk@gmail.com</CCEmail>
<Content>Content 4</Content>
</MailObject>
</AllEmails>

我的XSL输出应该是这样的:

<UniqueEmails>
<MailObject>
<ToEmail>abc@gmail.com</ToEmail>
<CCEmail>def@gmail.com</CCEmail>
<Content>Content 1, Content 2</Content>
</MailObject>
<MailObject>
<ToEmail>geh@gmail.com</ToEmail>
<CCEmail>ijk@gmail.com</CCEmail>
<Content>Content 3, Content 4</Content>
</MailObject>
</UniqueEmails>

基本上它需要检查唯一的&#34;到&#34;和&#34; cc&#34;电子邮件地址并组合这些节点的内容,并提供输出与其内容的连接。预期的结果是不要将相同的内容重复发送到相同的电子邮件地址,而是连接并在电子邮件地址相同时将其作为一封电子邮件发送。

1 个答案:

答案 0 :(得分:0)

一种解决方案是使用Muenchian Grouping。要匹配两个不同值具有相同值的元素,可以使用连接值的键:
<xsl:key name="mailkey" match="MailObject" use="concat(ToEmail,CCEmail)"/>

遵循XSLT

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"  omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:key name="mailkey" match="MailObject" use="concat(ToEmail,CCEmail)"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="AllEmails">
    <UniqueEmails>
      <xsl:for-each select="MailObject[count(. | key('mailkey',  
                            concat(ToEmail,CCEmail))[1]) = 1]">
      <xsl:variable name="current" select="concat(ToEmail,CCEmail)"/>
      <xsl:copy>
        <xsl:apply-templates select="@*|node()[not(name()='Content')]"/>
          <Content>
            <xsl:for-each select="//MailObject[concat(ToEmail,CCEmail)=$current]">
              <xsl:value-of select="Content"/>
                <xsl:if test="position() != last()">
                  <xsl:text>,</xsl:text>
                </xsl:if>
            </xsl:for-each>
          </Content>
        </xsl:copy>
      </xsl:for-each>
    </UniqueEmails>
  </xsl:template>
</xsl:transform>

当应用于您的输入时,XML会生成输出

<UniqueEmails>
   <MailObject>
      <ToEmail>abc@gmail.com</ToEmail>
      <CCEmail>def@gmail.com</CCEmail>
      <Content>Content 1,Content 2</Content>
   </MailObject>
   <MailObject>
      <ToEmail>geh@gmail.com</ToEmail>
      <CCEmail>ijk@gmail.com</CCEmail>
      <Content>Content 3,Content 4</Content>
   </MailObject>
</UniqueEmails>

有关使用Muenchian方法进行分组的详细说明,请查看上面提供的链接中的文章 select="MailObject[count(. | key('mailkey', concat(ToEmail,CCEmail))[1]) = 1]"循环中的xsl:for-each选择具有值MailObectToEmail的串联值相同的所有唯一CCEmail元素。在此循环中,将复制所有匹配的MailObject元素,但省略子节点Content

<xsl:apply-templates select="@*|node()[not(name()='Content')]"/>

相反,会生成一个新的Content元素,其中ContentMailObject个子元素的值具有相同的ToEmailCCEmail值作为当前MailObject

<xsl:for-each select="//MailObject[concat(ToEmail,CCEmail)=$current]">
  <xsl:value-of select="Content"/>

如果它不是最后一个元素,则使用position()last()添加,

<xsl:if test="position() != last()">
  <xsl:text>,</xsl:text>
</xsl:if>