1

I have a requirement to find duplicate and empty nodes instead of removing them from the XML, so i wrote below XSL and am able to get the list of empty nodes by reading the XML.But am not able to get the result if Duplicate node exists. need your help to achieve this.

below is the input XML:

    <p:Organisation xmlns:p="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd HeaderRecords.xsd ">
  <p:EMP>
    <p:ID>123</p:ID>
    <p:Name>uday</p:Name>
    <p:Designation>SoftwareEng</p:Designation>
    <p:ExpertiseIn>SOA,OSB,TIBCO</p:ExpertiseIn>
  </p:EMP>
  <p:ASSETS>
    <p:ASSET>
      <p:AssetID>1000</p:AssetID>
      <p:Name>Ego</p:Name>
      <p:InUse>yes</p:InUse>
      <p:AssignedDate>2005</p:AssignedDate>
    </p:ASSET>
    <p:ASSET>
      <p:AssetID>2000</p:AssetID>
      <p:Name>HP</p:Name>
      <p:InUse></p:InUse>
      <p:AssignedDate>2002</p:AssignedDate>
    </p:ASSET>
    <p:ASSET>
      <p:AssetID>3000</p:AssetID>
      <p:Name>Dell</p:Name>
      <p:InUse>yes</p:InUse>
      <p:AssignedDate>2010</p:AssignedDate>
    </p:ASSET>
    <p:ASSET>
      <p:AssetID>4000</p:AssetID>
      <p:Name></p:Name>
      <p:InUse>yes</p:InUse>
      <p:AssignedDate>2009</p:AssignedDate>
    </p:ASSET>
    <p:ASSET>
      <p:AssetID>3000</p:AssetID>
      <p:Name>Lenovo</p:Name>
      <p:InUse>yes</p:InUse>
      <p:AssignedDate>2011</p:AssignedDate>
    </p:ASSET>
  </p:ASSETS>
</p:Organisation>

and below is the current output i get if i see any empty nodes:

InUse in Line- 2 with Position-3 is empty               


Name in Line- 4 with Position-2 is empty    

below is the expected Output :

    InUse in Line- 2 with Position-3 is empty               

   Name in Line- 4 with Position-2 is empty             

   Found Duplicate Asset ID's

below is the XSLT that i have worked and able to get till list of empty nodes:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd">
<xsl:output omit-xml-declaration="yes" />

<xsl:template match="/">
    <xsl:apply-templates mode="rule1"
        select="p:Organisation/p:EMP/p:ID">
    </xsl:apply-templates>
    <xsl:apply-templates mode="rule2"
        select="p:Organisation/p:EMP/p:Name">
    </xsl:apply-templates>
    <xsl:apply-templates mode="rule3"
        select="p:Organisation/p:EMP/p:Designation">
    </xsl:apply-templates>
    <xsl:apply-templates mode="rule4"
        select="p:Organisation/p:EMP/p:ExpertiseIn">
    </xsl:apply-templates>

    <xsl:apply-templates mode="rule5"
        select="p:Organisation/p:ASSETS">
    </xsl:apply-templates>

</xsl:template>

                                            <!-- Employee data Validation -->

<xsl:template match="p:ID" mode="rule1">
    <xsl:if test="current()  = ''">
    Employee ID is empty.
    </xsl:if>
</xsl:template>
<xsl:template match="p:Name" mode="rule2">
    <xsl:if test="current() = ''">
    Employee Name is empty.
    </xsl:if>           
</xsl:template>
<xsl:template match="p:Designation" mode="rule3">
    <xsl:if test="current() = ''">
    Employee Designation is empty.
    </xsl:if>   
</xsl:template>
<xsl:template match="p:ExpertiseIn" mode="rule4">
    <xsl:if test="current() = ''">
    ExpertiseIn data can't be empty.
    </xsl:if>       
</xsl:template> 

                                            <!-- Assets data Validation -->

<xsl:template match="p:ASSETS/*" mode='rule5'>
    <xsl:variable name="i" select="count(preceding-sibling::*)+1" />
    <xsl:for-each select="child::*">
        <xsl:if test="current() = '' ">         
        <xsl:value-of select="local-name()" /> in Line- <xsl:value-of select="$i" /> with Position-<xsl:value-of select="count(preceding-sibling::*)+1" /> is empty             
        </xsl:if>
    </xsl:for-each>
</xsl:template> 

please help me in finding duplicate nodes too.

Thanks for your helping hands.

3
  • Please show us the expected result. Commented Oct 13, 2016 at 20:08
  • thanks for your response michael, i have added expected output in post. please see. Commented Oct 13, 2016 at 20:30
  • You even don't need any XSLT conditional operator -- see details in my answer. Commented Oct 14, 2016 at 2:14

3 Answers 3

1

This short and simple transformation produces a space-separated list of all p:AssetID elements that have duplicate values:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:p="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd">
 <xsl:output method="text"/>
 <xsl:key name="kAsseIdByVal" match="p:AssetID" use="."/>

  <xsl:template match="p:AssetID[generate-id()=generate-id(key('kAsseIdByVal', .)[2])]">
    <xsl:value-of select="concat(., ' ')"/>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>

When applied on this XML document (the provided one + one more pAsset element to have one more group of duplicate values):

<p:Organisation xmlns:p="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd HeaderRecords.xsd ">
    <p:EMP>
        <p:ID>123</p:ID>
        <p:Name>uday</p:Name>
        <p:Designation>SoftwareEng</p:Designation>
        <p:ExpertiseIn>SOA,OSB,TIBCO</p:ExpertiseIn>
    </p:EMP>
    <p:ASSETS>
        <p:ASSET>
            <p:AssetID>1000</p:AssetID>
            <p:Name>Ego</p:Name>
            <p:InUse>yes</p:InUse>
            <p:AssignedDate>2005</p:AssignedDate>
        </p:ASSET>
        <p:ASSET>
            <p:AssetID>2000</p:AssetID>
            <p:Name>HP</p:Name>
            <p:InUse></p:InUse>
            <p:AssignedDate>2002</p:AssignedDate>
        </p:ASSET>
        <p:ASSET>
            <p:AssetID>3000</p:AssetID>
            <p:Name>Dell</p:Name>
            <p:InUse>yes</p:InUse>
            <p:AssignedDate>2010</p:AssignedDate>
        </p:ASSET>
        <p:ASSET>
            <p:AssetID>4000</p:AssetID>
            <p:Name></p:Name>
            <p:InUse>yes</p:InUse>
            <p:AssignedDate>2009</p:AssignedDate>
        </p:ASSET>
        <p:ASSET>
            <p:AssetID>3000</p:AssetID>
            <p:Name>Lenovo</p:Name>
            <p:InUse>yes</p:InUse>
            <p:AssignedDate>2011</p:AssignedDate>
        </p:ASSET>
        <p:ASSET>
            <p:AssetID>4000</p:AssetID>
            <p:Name></p:Name>
            <p:InUse>yes</p:InUse>
            <p:AssignedDate>2009</p:AssignedDate>
        </p:ASSET>
    </p:ASSETS>
</p:Organisation>

the wanted, correct result is produced:

3000 4000 
Sign up to request clarification or add additional context in comments.

Comments

0

To minimize the example to the problem at hand, consider the following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://www.tibco.com/schemas/prjDelimeter/Schema/Schema2.xsd">
<xsl:output method="text" encoding="UTF-8" />

<xsl:key name="asset" match="p:ASSET" use="p:AssetID" />

<xsl:template match="/p:Organisation">
    <!-- other stuff -->
    <xsl:if test="p:ASSETS/p:ASSET[count(key('asset', p:AssetID)) > 1]">Found Duplicate Asset ID's</xsl:if>
</xsl:template>

</xsl:stylesheet>

1 Comment

that helped me a lot michael, till now i tried to achieve it by using generate-id()=key('',.). but this really worked for me
0

i just figured out that even we can achieve this requirement with generate-id() concept as below:

<xsl:if test="p:ASSETS/p:ASSET[generate-id()= generate-id(key('asset',p:AssetID)[2])]">Found Duplicate Asset ID's</xsl:if>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.