Re: spot/remove repeated elements in XML documet

Manuel Souto Pico <[email protected]>
Newsgroups gmane.comp.lang.perl.xml
Message-ID <[email protected]>
Hi again, Michael,

Thanks for your reply. Indeed, XSLT seems like the easiest option to do 
this processing. However, I don't have enough knowledge about XLST in 
order to understand well some things in your proposal, I might need to 
study a bit...

I will ask about one only: <xsl:variable name="unlikely" 
select="'||--||'"/>. I understand this is what might be between elements 
Eng and Spa, but I don't understand the '||--||'. Could you explain?

Anyway, I tried to use your template to process my example (which is a 
simplified version of the document that I need to process) but I get 
some errors (in Oxygen). Using XSLT 1.0, the line <xsl:key name="dupl" 
match="entry" use="concat( Eng, $unlikely, Spa)"/> gives the error: "The 
expressions in xsl:key may not contain references to variables". Using 
2.0, it is the line generate-id( key( 'dupl', $lookup-key)[ 1 ] )"> that 
gives the same error.

However, using the Muenchian grouping thing, I've done some tests on my 
side and I've mananged to come up with this (please tell me whether it 
should be more appropriate to post this in the list for XSL):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
version="1.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:key name="eng-by-content" match="entry/Eng" use="."/>
    <xsl:key name="spa-by-content" match="entry/Spa" use="."/>
    <xsl:template match="/dictionary">
        <dictionary>
            <xsl:for-each select="entry/Eng">
                <xsl:if test="generate-id(.) =
                generate-id(key('eng-by-content', .)[1]) ">
                    <text>
                        <eng>
                            <xsl:value-of select="."/>
                        </eng>
                        <spa>
                            <xsl:value-of select="../Spa/."/>
                        </spa>
                    </text>
                </xsl:if>
            </xsl:for-each>
        </dictionary>
    </xsl:template>
</xsl:stylesheet>

for the data (note the added root element):
<?xml version="1.0" encoding="UTF-8"?>
<dictionary>
    <entry id="1">
        <Eng>house</Eng>
        <Spa>casa</Spa>
    </entry>
    <entry id="2">
        <Eng>shoe</Eng>
        <Spa>zapato</Spa>
    </entry>
    <entry id="3">
        <Eng>house</Eng>
        <Spa>casa</Spa>
    </entry>
    <entry id="4">
        <Eng>house</Eng>
        <Spa>morada</Spa>
    </entry>   
</dictionary>

This XSL sheet allows me to output only the entries with no duplicate 
English term (say, 1 and 2), and that's already something. I've tried 
applying your concatenation syntax but I can't manage to use both 
languages as criteria (to output entries 1, 2 and *4* but not 3). That's 
what I have so far.

Thanks a lot for your help!
Manuel


Michael Ludwig escribió:
> Manuel Souto Pico schrieb:
>
>   
>>    <entry ="10">
>>       <Eng>house</Eng>
>>       <Spa>casa</Spa>
>>    </entry>
>>     
>
> The <entry> element, of course, is not valid.
>
>   
>>    <entry ="12">
>>       <Eng>house</Eng>
>>       <Spa>casa</Spa>
>>    </entry>
>>     
>
>   
>> where as you can see, entries 10 and 12 have identical contents.
>>
>> My question is: Is there any easy way to spot and/or remove repeated
>> elements? I suppose it could be done with XSL or a perl module for
>> XML...
>>     
>
> It is not complicated. First, define identity. In your case, that may be
> the concatenation of <Eng> and <Spa>. (It might also be something else.)
>
> Then, in XSLT 2.0 it would be really easy. But with Perl, you only have
> XSLT 1.0 at your disposal.
>
> Here's an XSLT 1.0 solution. The algorithm is simple: Find duplicates
> and eliminate all but the first one. The implementation may not be
> obvious at first sight, but it is not difficult. Do some googling for
> "Muenchian Grouping".
>
> Michael Ludwig
>
> <?xml version="1.0" encoding="ISO-8859-1"?>
> <xsl:stylesheet version="1.0"
>    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>
>    <xsl:variable name="unlikely" select="'||--||'"/>
>    <xsl:key name="dupl" match="entry" use="concat( Eng, $unlikely, Spa)"/>
>
>    <xsl:template match="document">
>      <xsl:apply-templates select="entry"/>
>    </xsl:template>
>
>    <xsl:template match="entry">
>      <xsl:variable name="lookup-key" select="concat(Eng, $unlikely, Spa)"/>
>      <xsl:if test="
>        generate-id() =
>        generate-id( key( 'dupl', $lookup-key)[ 1 ] )">
>        <xsl:copy>
>          <xsl:apply-templates select="@*|node()"/>
>        </xsl:copy>
>      </xsl:if>
>    </xsl:template>
>
>    <xsl:template match="@*|node()">
>      <xsl:copy>
>        <xsl:apply-templates select="@*|node()"/>
>      </xsl:copy>
>    </xsl:template>
>
> </xsl:stylesheet>
> _______________________________________________
> Perl-XML mailing list
> [email protected]
> To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
>
>
>

_______________________________________________
Perl-XML mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.