Pergunta

I've seen lots of questions and solutions regarding determining unique nodes in XSLT and succeeded in getting that to work until I needed to evaluate the uniqueness using an expression.

Using this data file:

<root>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword2</field></data>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword2</field></data>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword2</field></data>
</root>

And this transform template:

<xsl:template match="/root">
    <xsl:for-each select="data[not(field=preceding-sibling::data/field)]">
        field=<xsl:value-of select="field"/>
    </xsl:for-each>
    <xsl:for-each select="data[not(substring-after(field,': ')=substring-after(preceding-sibling::data/field,': '))]">
        short_field=<xsl:value-of select="substring-after(field,': ')" />
    </xsl:for-each>
</xsl:template>

I get the following output:

field=find me: keyword1
field=find me: keyword2
short_field=keyword1
short_field=keyword2
short_field=keyword2
short_field=keyword2

The first for-each works as expected but once I process field using substring-after (because in reality the leading text won't always match), only the first value actually matches. Notice the two extra keyword2 values.

Can anybody explain this and propose a solution? I'm using MSXSL to perform this evaluation.

Foi útil?

Solução

I've seen lots of questions and solutions regarding determining unique nodes in XSLT

It's too bad you missed all the good ones - i.e. those dealing with Muenchian grouping. Try it this way:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:key name="field-by-suffix" match="field" use="substring-after(.,': ')" />

<xsl:template match="/">
    <xsl:for-each select="root/data/field[count(. | key('field-by-suffix', substring-after(.,': '))[1]) = 1]">
        <xsl:text>short_field=</xsl:text>
        <xsl:value-of select="substring-after(.,': ')" />
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

When applied to the following example input:

<root>
    <data><field>alpha: keyword1</field></data>
    <data><field>bravo: keyword2</field></data>
    <data><field>charlie delta: keyword1</field></data>
    <data><field>echo: keyword2</field></data>
    <data><field>foxtrot: keyword1</field></data>
    <data><field>golf hotel: keyword1</field></data>
    <data><field>echo: keyword2</field></data>
</root>

the result is:

short_field=keyword1
short_field=keyword2

Outras dicas

If you look at the output of:

<xsl:for-each select="data">
    <xsl:value-of select="substring-after(preceding-sibling::data/field,': ')"/>
    <xsl:text>&#10;</xsl:text>
</xsl:for-each>

you will see that in this case it is always getting the same value. In fact if you change the first field to something like keyword0 you will see that in your second loop you are always comparing to that first node. Also note that it only outputs 6 values when there are 7 in the data, because the first one is empty. The substring-after only processes a single node to compare to instead of all preceding-sibling:: nodes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top