Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking for a duplicate element in the OUTPUT

Tags:

xml

xslt

xslt-1.0

I've got some XML, for example purposes it looks like this:

<root>
    <field1>test</field1>
    <f2>t2</f2>
    <f2>t3</f2>
</root>

I want to transform it with XSLT, but I want to suppress the second f2 element in the output - how do I check inside my template to see if the f2 element already exists in the output when the second f2 element in the source is processed? My XSLT looks something like this at present:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="no" omit-xml-declaration="yes" standalone="no" />
  <xsl:template match="/">
    <xsl:for-each select="./root">
      <output>
        <xsl:apply-templates />        
      </output>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="*" >
      <xsl:element name="{name(.)}">
        <xsl:value-of select="." />
      </xsl:element>
  </xsl:template>
</xsl:stylesheet>

I need to do some sort of check around the xsl:element in the template I think, but I'm not sure how to interrogate the output document to see if the element is already present.

Edit: Forgot the pre tags, code should be visible now!

like image 896
Code Trawler Avatar asked Jan 24 '23 02:01

Code Trawler


2 Answers

It depends how system wide you want to be.

i.e. Are you only concerned with elements that are children of the same parent, or all elements at the same level ('cousins' if you like) or elements anywhere in the document...

In the first situation you could check the preceding-sibling axis to see if any other elements exist with the same name.

<xsl:if test="count(preceding-sibling::node()[name()=name(current())])=0">
  ... do stuff in here.
</xsl:if>
like image 86
samjudson Avatar answered Feb 02 '23 14:02

samjudson


To only check (and warn you of a duplicate), you may find an example here

Something along the lines of:

<xsl:for-each-group select="collection(...)//@id" group-by=".">
  <xsl:if test="count(current-group()) ne 1">
    <xsl:message>Id value <xsl:value-of select="current-grouping-key()"/> is 
       duplicated in files
       <xsl:value-of select="current-group()/document-uri(/)" separator=" and
    "/></xsl:message>
  </xsl:if>
 </xsl:for-each-group>

To be modified to select all nodes within 'root' element.

As to remove the duplicate lines, you have another example here

That would look like:

<xsl:stylesheet>
  <xsl:key name="xyz" match="record[x/y/z]" use="x/y/z" />
  <xsl:variable name="noxyzdups" select="/path/to/record[generate-id(.) = generate-id(key('xyz', x/y/z))]" />
...
  <xsl:template ... >
    <xsl:copy-of "exslt:node-set($noxyzdups)" />
  </xsl:template>
</xsl:stylesheet>

x/y/z is the xpath expression that you want made unique. It can be concat(x,'-',@y,'-',z) or whatever you want.

Now I am not sure those two examples can easily be adapted to your case, but I just wanted to point out those two sources, in case it helps.

like image 29
VonC Avatar answered Feb 02 '23 12:02

VonC