问题
I have a node in my XML data named this node contains a unique value, say 45678. Via XSLT, I'd like to only include this node's data, if 45678 is found more than once (1) in the complete data set. The end result can modify the existing node, or create a new one called . The end result of this data creates "Parent with children" products. The productId value groups all similar products together, the problem, is that sometimes there is only 1 product with that key, and I shouldn't create a parent product.
IMPORTANT NOTE: Why I'm struggling so much, is 1st, I'm still brand new to XSL, and second, the current version of the engine does not allow me to use EXSLT, but it appears I can use PHP if necessary.
Sample Data Set
<productId>0243176820</productId>
This value you can see is used multiple times, and in this case it should be included in the result data, <productId>1136194258</productId>
but this one is only included once.
Sample Data Below
<root>
<part>
<partNumber>06013464</partNumber>
<punctuatedPartNumber>0601-3464</punctuatedPartNumber>
<partStatusDescription>DISCONTINUED</partStatusDescription>
<partDescription>Flat Black 18" Handlebar</partDescription>
<unitOfMeasure>Each</unitOfMeasure>
<brandName>LA CHOPPERS</brandName>
<supplierNumber>LA-7321-18M</supplierNumber>
<specialInstructions/>
<baseDealerPrice>185.0000</baseDealerPrice>
<yourDealerPrice>185.0000</yourDealerPrice>
<baseRetailPrice>272.9500</baseRetailPrice>
<originalRetailPrice>272.9500</originalRetailPrice>
<partImage>http://asset.lemansnet.com/z/LzgvQS80LzhBNDg5QjE2LUNEQkMtNDAzMC04NkE0LTlEQjE1MDdGRDYzMQ==</partImage>
<productId>1136194258</productId>
<productName>1-1/4" Touring Ape Hanger Handlebar</productName>
</part>
<part>
<partNumber>06012660</partNumber>
<punctuatedPartNumber>0601-2660</punctuatedPartNumber>
<partStatusDescription>STANDARD</partStatusDescription>
<partDescription>Black 10" Handlebar</partDescription>
<unitOfMeasure>Each</unitOfMeasure>
<brandName>LA CHOPPERS</brandName>
<supplierNumber>LA-7321-10B</supplierNumber>
<specialInstructions/>
<baseDealerPrice>185.0000</baseDealerPrice>
<yourDealerPrice>185.0000</yourDealerPrice>
<baseRetailPrice>272.9500</baseRetailPrice>
<originalRetailPrice>272.9500</originalRetailPrice>
<partImage>http://asset.lemansnet.com/z/LzkvMC9DLzkwQzQ2MjZGLTQyOEItNDNGRi1CQjYwLTNBREMyOUM1REU4MQ==</partImage>
<productId>0243176820</productId>
<productName>1-1/4" Touring Ape Hanger Handlebar</productName>
</part>
<part>
<partNumber>06012663</partNumber>
<punctuatedPartNumber>0601-2663</punctuatedPartNumber>
<partStatusDescription>STANDARD</partStatusDescription>
<partDescription>Chrome 14" Handlebar</partDescription>
<unitOfMeasure>Each</unitOfMeasure>
<brandName>LA CHOPPERS</brandName>
<supplierNumber>LA-7321-14</supplierNumber>
<specialInstructions/>
<baseDealerPrice>185.0000</baseDealerPrice>
<yourDealerPrice>185.0000</yourDealerPrice>
<baseRetailPrice>272.9500</baseRetailPrice>
<originalRetailPrice>272.9500</originalRetailPrice>
<partImage>http://asset.lemansnet.com/z/LzcvNC81Lzc0NUE3OUM4LTBERDAtNDQ3NS1CMEFBLUVBMDUyRkUzN0Q5OA==</partImage>
<productId>0243176820</productId>
<productName>1-1/4" Touring Ape Hanger Handlebar</productName>
</part>
<part>
<partNumber>06011482</partNumber>
<punctuatedPartNumber>0601-1482</punctuatedPartNumber>
<partStatusDescription>STANDARD</partStatusDescription>
<partDescription>Black Beach Bar Handlebar</partDescription>
<unitOfMeasure>Each</unitOfMeasure>
<brandName>LA CHOPPERS</brandName>
<supplierNumber>LA-7312-01B</supplierNumber>
<specialInstructions/>
<baseDealerPrice>106.5000</baseDealerPrice>
<yourDealerPrice>106.5000</yourDealerPrice>
<baseRetailPrice>157.9500</baseRetailPrice>
<originalRetailPrice>157.9500</originalRetailPrice>
<partImage>http://asset.lemansnet.com/z/LzMvRS82LzNFNjlFOTdDLTg5NjEtNDU1MC1BRkY3LUExNjU0MTdEQUQ5MQ==</partImage>
<productId>0635669078</productId>
<productName>Hefty 1-1/4" Handlebar — Beach Bar/Hefty</productName>
</part>
</root>
Current XSLT that processes the data, where everything else works except the commented out section.
<?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:template match="root">
<xsl:element name="items">
<xsl:for-each select="part">
<xsl:if test="supplierNumber != '' and partStatusDescription != 'DISCONTINUED' ">
<xsl:element name="item">
<partNumber>
<xsl:value-of select="partNumber"/>
</partNumber>
<xsl:element name="name">
<xsl:value-of select="concat(brandName,' ',productName)"/>
</xsl:element>
<punctuatedPartNumber>
<xsl:value-of select="punctuatedPartNumber"/>
</punctuatedPartNumber>
<xsl:element name="is_in_stock">
<xsl:if test="partStatusDescription = 'STANDARD'">
<xsl:value-of select="1"/>
</xsl:if>
<xsl:if test="partStatusDescription != 'STANDARD'">
<xsl:value-of select="0"/>
</xsl:if>
</xsl:element>
<partDescription>
<xsl:value-of select="partDescription"/>
</partDescription>
<unitOfMeasure>
<xsl:value-of select="unitOfMeasure"/>
</unitOfMeasure>
<brandName>
<xsl:value-of select="brandName"/>
</brandName>
<supplierNumber>
<xsl:value-of select="supplierNumber"/>
</supplierNumber>
<specialInstructions>
<xsl:value-of select="specialInstructions"/>
</specialInstructions>
<xsl:element name="price">
<xsl:value-of select="(originalRetailPrice * 100) div 100"/>
</xsl:element>
<xsl:element name="special_price">
<xsl:if test="baseRetailPrice < originalRetailPrice">
<xsl:value-of select="baseRetailPrice"/>
</xsl:if>
</xsl:element>
<partImage>
<xsl:value-of select="partImage"/>
</partImage>
<productName>
<xsl:value-of select="productName"/>
</productName>
<productImage>
<xsl:value-of select="productImage"/>
</productImage>
<bullet1>
<xsl:value-of select="bullet1"/>
</bullet1>
<bullet2>
<xsl:value-of select="bullet2"/>
</bullet2>
<bullet3>
<xsl:value-of select="bullet3"/>
</bullet3>
<bullet4>
<xsl:value-of select="bullet4"/>
</bullet4>
<!-- finish -->
<xsl:choose>
<xsl:when test="contains(partDescription, 'Black')">
<finish>Black</finish>
</xsl:when>
<xsl:when test="contains(partDescription, 'Flat Back')">
<finish>Flat Back</finish>
</xsl:when>
<xsl:when test="contains(partDescription, 'Chrome')">
<finish>Chrome</finish>
</xsl:when>
</xsl:choose>
<!-- size -->
<xsl:call-template name="find-size">
<xsl:with-param name="text" select="partDescription"/>
</xsl:call-template>
<!-- I understand this wouldn't work as I'm just checking the total nodes, but I think someonehow I need to set the value of this node as a variable, and then check the count of this variable. This is easy in PHP, but I don't fully understand XSL -->
<xsl:if test="count(/root/part/configurable_id) > 1">
<xsl:element name="configurable_id">
<xsl:value-of select="productId"/>
</xsl:element>
</xsl:if>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="find-size">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
<xsl:choose>
<xsl:when test="starts-with(translate($token, '123456789', '000000000'), '0')">
<size>
<xsl:value-of select="$token"/>
</size>
</xsl:when>
<xsl:when test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="find-size">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
回答1:
To check the uniqueness of a value in XSLT 1.0, you can use a slight modification of Muenchian grouping.
Here's a minimal example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="part-by-product" match="part" use="productId" />
<xsl:template match="/root">
<items>
<xsl:for-each select="part[supplierNumber/text() and partStatusDescription != 'DISCONTINUED']">
<item>
<xsl:copy-of select="partNumber | productId"/>
<!-- check productId uniqueness -->
<xsl:if test="count(key('part-by-product', productId)) > 1">
<configurable_id>
<xsl:value-of select="productId"/>
</configurable_id>
</xsl:if>
</item>
</xsl:for-each>
</items>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, this will return:
Result
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<partNumber>06012660</partNumber>
<productId>0243176820</productId>
<configurable_id>0243176820</configurable_id>
</item>
<item>
<partNumber>06012663</partNumber>
<productId>0243176820</productId>
<configurable_id>0243176820</configurable_id>
</item>
<item>
<partNumber>06011482</partNumber>
<productId>0635669078</productId>
</item>
</items>
Unrelated to your question:
Note the use of a predicate instead of xsl:if
and literal result elements instead of xsl:element
to reduce the amount of code.
来源:https://stackoverflow.com/questions/65419245/xslt-1-0-output-count-of-value-uniqueness-in-a-node-with-vanilla-xslt-1-0-or-p