Search code examples
xmlreplacexslt-1.0mbeans

removing duplicates from xml file use xslt


Here is an example where i have two <mbean> sections with same name, but the properties in these sections are diffrent, I would like to merge these two <mbean> sections and duplicate propeties has to replace with the latest one that is added to bottom of <mbean> section.

        <mbean code="org.jboss.naming.JNDIBindingServiceMgr"
        name="abc.myconfig.jndi:name=myconfigAppPartitionJNDI">
        <attribute name="BindingsConfig" serialDataType="jbxb">
            <jndi:bindings
                xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:jndi="urn:jboss:jndi-binding-service:1.0"
                xs:schemaLocation="urn:jboss:jndi-binding-service:1.0 resource:jndi-binding-service_1_0.xsd">                   
                <jndi:binding
                    name="myabc/myconfig/myservice/myabcservice">
                    <jndi:value type="java.lang.String">
                        old-value
                    </jndi:value>
                </jndi:binding>
                <jndi:binding name="myabc/myconfig/myabcdefService/myabcdefServiceUrl">
                      <jndi:value type="java.lang.String">
                            @myabcdefService.myabcdefServiceUrl@
                      </jndi:value>
                </jndi:binding>
            </jndi:bindings> 
        </attribute>
    </mbean>
    <mbean code="org.jboss.naming.JNDIBindingServiceMgr"
        name="abc.myconfig.jndi:name=myconfigAppPartitionJNDI">
        <attribute name="BindingsConfig" serialDataType="jbxb">
            <jndi:bindings
                xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:jndi="urn:jboss:jndi-binding-service:1.0"
                xs:schemaLocation="urn:jboss:jndi-binding-service:1.0 resource:jndi-binding-service_1_0.xsd">                   
                <jndi:binding
                    name="myabc/myconfig/myservice/myabcservice">
                    <jndi:value type="java.lang.String">
                        new-value
                    </jndi:value>
                </jndi:binding>
                <jndi:binding name="myabc/myconfig/myabcdefService/myabcdefServiceUrl">
                      <jndi:value type="java.lang.String">
                            @myabcdefService.myabcdefServiceUrl@
                      </jndi:value>
                </jndi:binding>
                <jndi:binding name="myabc/myconfig/myabcdefService/myabcFileNet">
                      <jndi:value type="java.lang.String">
                            @myabcdefService.myabcFileNet@
                      </jndi:value>
                </jndi:binding>
            </jndi:bindings> 
        </attribute>
    </mbean>

Expected output is:

                <mbean code="org.jboss.naming.JNDIBindingServiceMgr"
        name="abc.myconfig.jndi:name=myconfigAppPartitionJNDI">
        <attribute name="BindingsConfig" serialDataType="jbxb">
            <jndi:bindings
                xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:jndi="urn:jboss:jndi-binding-service:1.0"
                xs:schemaLocation="urn:jboss:jndi-binding-service:1.0 resource:jndi-binding-service_1_0.xsd">                   
                <jndi:binding name="myabc/myconfig/myabcdefService/myabcdefServiceUrl">
                      <jndi:value type="java.lang.String">
                            @myabcdefService.myabcdefServiceUrl@
                      </jndi:value>
                </jndi:binding>
                <jndi:binding
                    name="myabc/myconfig/myservice/myabcservice">
                    <jndi:value type="java.lang.String">
                        new-value
                    </jndi:value>
                </jndi:binding>
                <jndi:binding name="myabc/myconfig/myabcdefService/myabcFileNet">
                      <jndi:value type="java.lang.String">
                            @myabcdefService.myabcFileNet@
                      </jndi:value>
                </jndi:binding>
            </jndi:bindings> 
        </attribute>
    </mbean>

Solution

  • You need to use Muenchian Method for removing duplicates

    XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
        <xsl:key name="mbeanName" match="//mbean/@name" use="."/>
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="mbean[not(generate-id(@name) = generate-id(key('mbeanName', @name)[1]))]"/>
    </xsl:stylesheet>
    

    XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
        <mbean code="org.jboss.naming.JNDIBindingServiceMgr" name="abc.myconfig.jndi:name=myconfigAppPartitionJNDI">
            <attribute name="BindingsConfig" serialDataType="jbxb">
                <jndi:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:jndi="urn:jboss:jndi-binding-service:1.0" xs:schemaLocation="urn:jboss:jndi-binding-service:1.0 resource:jndi-binding-service_1_0.xsd">
                    <jndi:binding name="myabc/myconfig/myservice/myabcservice">
                        <jndi:value type="java.lang.String">
                            old-value
                        </jndi:value>
                    </jndi:binding>
                    <jndi:binding name="myabc/myconfig/myabcdefService/myabcdefServiceUrl">
                        <jndi:value type="java.lang.String">
                                @myabcdefService.myabcdefServiceUrl@
                          </jndi:value>
                    </jndi:binding>
                </jndi:bindings>
            </attribute>
        </mbean>
        <mbean code="org.jboss.naming.JNDIBindingServiceMgr" name="abc.myconfig.jndi:name=myconfigAppPartitionJNDI">
            <attribute name="BindingsConfig" serialDataType="jbxb">
                <jndi:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:jndi="urn:jboss:jndi-binding-service:1.0" xs:schemaLocation="urn:jboss:jndi-binding-service:1.0 resource:jndi-binding-service_1_0.xsd">
                    <jndi:binding name="myabc/myconfig/myservice/myabcservice">
                        <jndi:value type="java.lang.String">
                            new-value
                        </jndi:value>
                    </jndi:binding>
                    <jndi:binding name="myabc/myconfig/myabcdefService/myabcdefServiceUrl">
                        <jndi:value type="java.lang.String">
                                @myabcdefService.myabcdefServiceUrl@
                          </jndi:value>
                    </jndi:binding>
                    <jndi:binding name="myabc/myconfig/myabcdefService/myabcFileNet">
                        <jndi:value type="java.lang.String">
                                @myabcdefService.myabcFileNet@
                          </jndi:value>
                    </jndi:binding>
                </jndi:bindings>
            </attribute>
        </mbean>
    </root>
    

    OUTPUT:

    <root>
        <mbean code="org.jboss.naming.JNDIBindingServiceMgr" name="abc.myconfig.jndi:name=myconfigAppPartitionJNDI">
            <attribute name="BindingsConfig" serialDataType="jbxb">
                <jndi:bindings xmlns:jndi="urn:jboss:jndi-binding-service:1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="urn:jboss:jndi-binding-service:1.0 resource:jndi-binding-service_1_0.xsd">
                    <jndi:binding name="myabc/myconfig/myservice/myabcservice">
                        <jndi:value type="java.lang.String">
                            old-value
                        </jndi:value>
                    </jndi:binding>
                    <jndi:binding name="myabc/myconfig/myabcdefService/myabcdefServiceUrl">
                        <jndi:value type="java.lang.String">
                                @myabcdefService.myabcdefServiceUrl@
                          </jndi:value>
                    </jndi:binding>
                </jndi:bindings>
            </attribute>
        </mbean>
    </root>
    

    UPDATED XSLT:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
        <xsl:key name="mbeanName" match="//mbean/@name" use="."/>
        <xsl:key name="mbeanCount" match="//mbean[generate-id(@name) = generate-id(key('mbeanName', @name)[1])]" use="count(.)"/>
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="mbean[count(. | key('mbeanCount', /mbean/@name))]" />
    </xsl:stylesheet>