XSLT skips duplicate element

I start with XSLT.

My source XML is as follows:

<Passengers> <Passenger type="A" id="P1"/> <Passenger type="A" id="P2"/> <Passenger type="B" id="P3"/> <Passenger type="C" id="P4"/> </Passengers> 

The conclusion should be as follows:

 <Pax_Items> <Item> <Type>A</Type> <Count>2</Count> </Item> <Item> <Type>B</Type> <Count>1</Count> </Item> <Item> <Type>C</Type> <Count>1</Count> </Item> </Pax_Items> 

I created XSLT as below

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" exclude-result-prefixes="xmlns"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> <xsl:variable name="filter" select="'TK,AJ'"/> <xsl:template match="Passengers"> <xsl:element name="Pax_Items"> <xsl:apply-templates select="Passenger"/> </xsl:element> </xsl:template> <xsl:template match="Passenger"> <xsl:element name="Item"> <xsl:element name="Type"> <xsl:value-of select="@type"/> </xsl:element> <xsl:element name="Count"> <xsl:value-of select="count(//Passenger[@type=current()/@type])"/> </xsl:element> </xsl:element> </xsl:template> </xsl:stylesheet> 

With the above XSLT, I got the following result:

 <Pax_Items> <Item> <Type>A</Type> <Count>2</Count> </Item> <Item> <Type>A</Type> <Count>2</Count> </Item> <Item> <Type>B</Type> <Count>1</Count> </Item> <Item> <Type>C</Type> <Count>1</Count> </Item> </Pax_Items> 

How can I skip or skip a duplicate element? Please, help.

+4
source share
2 answers

Update your passenger template as follows; I added, if the condition for checking duplicate nodes,

 <xsl:template match="Passenger"> <xsl:if test="not(preceding-sibling::Passenger[@type = current()/@type])"> <xsl:element name="Item"> <xsl:element name="Type"> <xsl:value-of select="@type"/> </xsl:element> <xsl:element name="Count"> <xsl:value-of select="count(//Passenger[@type=current()/@type])"/> </xsl:element> </xsl:element> </xsl:if> </xsl:template> 
+2
source

This is actually a good example of a grouping problem. In XSLT1.0, the most efficient way to group is the Muenchian Grouping method, so it would be useful to know about it.

In this case, you want to group Passenger elements by their @type attribute, so you must define a key for this

 <xsl:key name="Passengers" match="Passenger" use="@type"/> 

Then you need to select the Passenger elements, which are the first occurrence of this element in the group for their @type attribute. This is done as follows:

 <xsl:apply-templates select="Passenger[generate-id() = generate-id(key('Passengers', @type)[1])]"/> 

Note the use of generate-id , which generates a unique identifier for node, allowing you to compare two nodes.

Then, to count the number of occurrences in a group, this is straightforward

 <xsl:value-of select="count(key('Passengers', @type))"/> 

Here is the full XSLT

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> <xsl:key name="Passengers" match="Passenger" use="@type"/> <xsl:template match="Passengers"> <Pax_Items> <xsl:apply-templates select="Passenger[generate-id() = generate-id(key('Passengers', @type)[1])]"/> </Pax_Items> </xsl:template> <xsl:template match="Passenger"> <Item> <Type> <xsl:value-of select="@type"/> </Type> <Count> <xsl:value-of select="count(key('Passengers', @type))"/> </Count> </Item> </xsl:template> </xsl:stylesheet> 

When applied to your sample XML, the following is output

 <Pax_Items> <Item> <Type>A</Type> <Count>2</Count> </Item> <Item> <Type>B</Type> <Count>1</Count> </Item> <Item> <Type>C</Type> <Count>1</Count> </Item> </Pax_Items> 

Also note that there is no real reason to use xsl: element to display static elements. Just write the item directly.

+7
source

Source: https://habr.com/ru/post/1442048/


All Articles