XSLT Gouping,for-each和implicated loop。如何消除重复?

时间:2012-03-28 13:21:46

标签: xslt loops foreach grouping duplicate-removal

希望找到一位大师的帮助来找出下一个问题。

我有两个xml文件。这里有第一个( text.xml ):

<text>
<ref>Author1, Title1, Date1</ref>
<ref>Author75, Title75, Date2</ref>
<ref>Author2, Title2, Date2</ref>
<ref>Author3, Title3, Date3</ref>
<text>

第二个像这样( list.xml ):

<list>
<bibl xml:id="1"><author>Author1</author><date>Date1</date></bibl>
<bibl xml:id="2"><author>Author2</author><date>Date2</date></bibl>
<bibl xml:id="3"><author>Author3</author><date>Date3</date></bibl>
</list>

我想查询 text.xml 并检查 list.xml 以将@xml:id(来自 list.xml )添加到<ref>(来自 text.xml )包含相同的作者和日期。如果没有,则只需复制原始<ref>

所以我想获得:

<ref xml:id="1">Author1, Title1, Date1</ref> 
<ref>Author75, Title75, Date2</ref>
<ref xml:id="2>Author2, Title2, Date2</ref>
etc.

我的 XSLT 很好地识别所有相关信息:

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

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

    <xsl:template match="ref">
        <xsl:variable name="ref" select="."/>
        <xsl:for-each select="document('list.xml')//bibl">
            <xsl:variable name="bibl" select="."/>
            <xsl:variable name="author" select="author"/>
            <xsl:variable name="date" select="date"/>
            <xsl:choose>
                <xsl:when test="contains($ref, $author) and contains($ref, $date)">
                    <ref>
                        <xsl:attribute name="xml:id">
                            <xsl:value-of select="$bibl/@xml:id"/>
                        </xsl:attribute>
                        <xsl:value-of select="$ref"/>
                    </ref>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$ref"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

但是,然后没有相应的不仅是复制权<ref>,而是复制所有<ref>我在第二个文件中拥有<bibl>个节点的时间。

问题出在<xsl:otherwise><xsl:copy-of select="$ref"/></xsl:otherwise>。 任何想法我如何才能获得我需要的这个独特的价值?我知道它实际上必须非常简单,我尝试使用key,generate-id,for-each-groups,distinct-values,但无法弄明白。

2 个答案:

答案 0 :(得分:0)

编辑: 嗯......过分关注xsl语法,我应该早点看到...... 每个ref上都有一个牵连的外循环,每个bibl上都有一个内循环。无论是匹配还是不匹配,您为每biblref生成一个元素。 因此,代替xsl:otherwise,您需要在for-each循环后检查是否没有匹配,如果需要,请执行copy-of

不确定如何进行检查,但是..可能使用生成的position()的{​​{1}}和count(),对不起...没有时间去思考关于这一点。

<击> 不是解释,而是解决方法:

<ref>

我的猜测是问题在于$ ref,那时候不是xpath表达式(如果我正确记得xsl-t)

答案 1 :(得分:0)

问题在于,无论是否存在匹配,您都要为 for-each 循环的每次迭代创建 ref 元素。

在这种情况下,您需要做的是在 for-each 之外创建 ref 元素,然后只为循环内的匹配元素创建id属性

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="ref">
      <xsl:variable name="ref" select="."/>
      <ref>
         <xsl:apply-templates select="@* "/>
         <xsl:for-each select="document('list.xml')//bibl">
            <xsl:variable name="bibl" select="."/>
            <xsl:variable name="author" select="author"/>
            <xsl:variable name="date" select="date"/>
            <xsl:choose>
               <xsl:when test="contains($ref, $author) and contains($ref, $date)">
                  <xsl:attribute name="xml:id">
                     <xsl:value-of select="$bibl/@xml:id"/>
                  </xsl:attribute>
               </xsl:when>
            </xsl:choose>
         </xsl:for-each>
         <xsl:apply-templates select="node()"/>
      </ref>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

<text>
   <ref xml:id="1">Author1, Title1, Date1</ref>
   <ref>Author75, Title75, Date2</ref>
   <ref xml:id="2">Author2, Title2, Date2</ref>
   <ref xml:id="3">Author3, Title3, Date3</ref>
</text>

但是,您当前的方法效率不高,因为每个 ref 元素都会迭代所有 bibl 元素。另一种方法是从 ref 元素中提取作者和日期,然后直接查找 bibl 元素

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="ref">
      <xsl:variable name="author" select="normalize-space(substring-before(., ','))"/>
      <xsl:variable name="date" select="normalize-space(substring-after(substring-after(., ','), ','))"/>
      <ref>
         <xsl:apply-templates select="@* "/>
         <xsl:apply-templates select="document('list.xml')//bibl[author=$author][date=$date]"/>
         <xsl:apply-templates select="node()"/>
      </ref>
   </xsl:template>

   <xsl:template match="bibl">
      <xsl:attribute name="xml:id">
         <xsl:value-of select="@xml:id"/>
      </xsl:attribute>
   </xsl:template>
</xsl:stylesheet>

这也应该给出相同的结果。