使用XSLT移除XML重复节点的技术咨询
Got it, let's break down how to solve your XSLT deduplication needs for both Message1 and Message2. I'll walk you through each requirement with concrete, tested code examples:
Requirement 1: Deduplicate <sObject> in <ns0:Message1> by AccountId + ContactId Combination
The core approach here uses Muenchian Grouping—a reliable method in XSLT 1.0 to group nodes by a unique key. We'll group <sObject> nodes based on the combined value of their <AccountId> and <ContactId> children, then only keep the first occurrence of each unique pair.
First, make sure to replace http://your-namespace-uri with the actual namespace URI from your source XML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://your-namespace-uri"> <!-- Identity template: copies all nodes/attributes by default (preserves non-targeted content) --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Target <sObject> nodes inside <ns0:Message1> --> <xsl:template match="ns0:Message1/UpdateMultipleObjectsOperationsSchema/sObject"> <!-- Define grouping key: concatenate AccountId and ContactId with a separator to avoid collisions --> <xsl:key name="uniqueSObjectPair" match="ns0:Message1/UpdateMultipleObjectsOperationsSchema/sObject" use="concat(AccountId, '||', ContactId)"/> <!-- Only keep the first instance of each unique AccountId+ContactId pair --> <xsl:if test="generate-id() = generate-id(key('uniqueSObjectPair', concat(AccountId, '||', ContactId))[1])"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:if> </xsl:template>
Requirement 2: Handle Duplicate <UpdateMultipleObjectsOperationsSchema> in <ns0:Message2>
You mentioned <UpdateMultipleObjectsOperationsSchema> might repeat here—let's cover two common scenarios you might be dealing with:
Scenario A: Deduplicate the entire <UpdateMultipleObjectsOperationsSchema> node
If you want to remove duplicate full instances of the schema node (based on its complete content), use grouping on the node's string value:
<!-- Add this template to the stylesheet above --> <xsl:template match="ns0:Message2/UpdateMultipleObjectsOperationsSchema"> <xsl:key name="uniqueSchema" match="ns0:Message2/UpdateMultipleObjectsOperationsSchema" use="string(.)"/> <xsl:if test="generate-id() = generate-id(key('uniqueSchema', string(.))[1])"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet>
Scenario B: Deduplicate <sObject> inside <UpdateMultipleObjectsOperationsSchema> (same rule as Requirement 1)
If the schema nodes themselves are unique, but their internal <sObject> nodes need deduplication by AccountId+ContactId, reuse the grouping logic but target the Message2 context:
<!-- Add this template instead for Scenario B --> <xsl:template match="ns0:Message2/UpdateMultipleObjectsOperationsSchema/sObject"> <xsl:key name="message2UniqueSObjectPair" match="ns0:Message2/UpdateMultipleObjectsOperationsSchema/sObject" use="concat(AccountId, '||', ContactId)"/> <xsl:if test="generate-id() = generate-id(key('message2UniqueSObjectPair', concat(AccountId, '||', ContactId))[1])"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet>
Quick Notes:
- The
||separator in the concatenated key prevents false matches (e.g., AccountId "123" + ContactId "45" won't be confused with AccountId "12" + ContactId "345"). - This uses XSLT 1.0 syntax, which works across all major processors. If you're using XSLT 2.0+, you could simplify grouping with
xsl:for-each-group, but the Muenchian approach is universally compatible.
内容的提问来源于stack exchange,提问作者amitz27

