Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Duplicate xml elements

i have to duplicate the xml payload into as many xml payloads based on a specific id, e.g., userid

<ns2:Details xmlns:ns2="ns">
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>46</ns2:UserId>
  <ns2:UserId>237</ns2:UserId>
</ns2:Details>

i need the output as

<ns2:Details>
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>46</ns2:UserId>
</ns2:Details>
<ns2:Details>
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>237</ns2:UserId>
</ns2:Details>

is this possible


Update: The below answer that was given is working fine, but there's a small catch I failed to mention. If the userid is the same and it's repeating, then the same xml payload should be displayed. For this I tried the following to get the unique elements of userid

<xsl:param name="userId" select="ns0:UserId[generate-id(.)=generate-id(key('k', ns0:UserId)[1])]"/>

but this is not working and also tried using above

..[generate-id(.)=generate-id(key('k', ns0:UserId)[1])] 

at template level also it is not working

Am I missing something?

Update : i made a small modification to the above code, instead of working at xsl:param, i have used it at xsl:apply-template

before modification (provided as answer to me) <xsl:apply-templates select="//ns2:Details/ns2:UserId"/> after modification <xsl:apply-templates select="//ns2:Details/ns2:UserId[generate-id(.)=generate-id(key('myUserId', .)[1])]"/>

my mistake i was using ns2:userid instead of "."

full xsl code ---


<xsl:output method="xml" indent="yes"/> <xsl:key name="k" match="ns2:UserId" use="text()"/> <xsl:key name="myUserId" match="ns2:UserId" use="."/> <xsl:template match="/"> <ns2:Root> <xsl:apply-templates select="//ns2:Details/ns2:UserId[generate-id(.)=generate-id(key('myUserId', .)[1])]"/> </ns2:Root> </xsl:template>

<xsl:template match="//ns2:Details"> <xsl:param name="userId" select="ns2:UserId"/> <ns2:Details> <xsl:copy-of select="key('k', $userId)[1]"/> <!-- displays UserId values--> <xsl:copy-of select="./*[name() != 'ns2:UserId']"/> <!-- displays other values--> </ns2:Details> </xsl:template>

<xsl:template match="ns2:UserId"> <xsl:apply-templates select=".."> <xsl:with-param name="userId" select="."/> </xsl:apply-templates> </xsl:template>

Please, validate it. this too is working for me...

like image 358
738560 Avatar asked Jul 12 '11 13:07

738560


People also ask

Can XML have duplicate elements?

Duplicate XML schema definitionsImported XSD and WSDL files can contain duplicate XML element type schema definitions. At run time, these duplicate definitions are treated as different Java object types, even though they are referenced by the same business object type and namespace.

How do I find duplicates in XML?

We first use the nodes function to convert from XML to relational data, then use value to get the text inside the Name node. We then put the result of the previous step into a CTE, and use a simple group by to get the value with multiple occurences.


2 Answers

Supposed XML:

<ns2:Details xmlns:ns2="ns2">
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>46</ns2:UserId>
  <ns2:UserId>237</ns2:UserId>
  <ns2:UserId>46</ns2:UserId>
</ns2:Details>

XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ns2="ns2"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="k" match="ns2:UserId" use="text()"/>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="//ns2:Details/ns2:UserId[not(node() = preceding-sibling::node())]"/>
    </root>
  </xsl:template>

  <xsl:template match="//ns2:Details">
    <xsl:param name="userId" select="ns2:UserId"/>

    <ns2:Details>
      <xsl:copy-of select="key('k', $userId)[not(node() = preceding-sibling::node())]"/>
      <xsl:copy-of select="./*[name() != 'ns2:UserId']"/>
    </ns2:Details>
  </xsl:template>

  <xsl:template match="ns2:UserId">
    <xsl:apply-templates select="..">
      <xsl:with-param name="userId" select="."/>
    </xsl:apply-templates>
  </xsl:template>

</xsl:stylesheet>

Output XML:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:ns2="ns2">
  <ns2:Details>
    <ns2:UserId>46</ns2:UserId>
    <ns2:var1>AA0511201143</ns2:var1>
    <ns2:var2>PARCEL</ns2:var2>
    <ns2:var3>04/04/2011</ns2:var3>
    <ns2:var4>Organization</ns2:var4>
  </ns2:Details>
  <ns2:Details>
    <ns2:UserId>237</ns2:UserId>
    <ns2:var1>AA0511201143</ns2:var1>
    <ns2:var2>PARCEL</ns2:var2>
    <ns2:var3>04/04/2011</ns2:var3>
    <ns2:var4>Organization</ns2:var4>
  </ns2:Details>
</root>
like image 160
Kirill Polishchuk Avatar answered Oct 23 '22 01:10

Kirill Polishchuk


This transformation (short, only two templates, no xsl:for-each, no modes):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns2="ns">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kIdByVal" match="ns2:UserId" use="."/>

 <xsl:template match="/">
  <xsl:apply-templates select=
  "ns2:Details/ns2:UserId
        [generate-id()=generate-id(key('kIdByVal',.)[1])]
  "/>
 </xsl:template>

 <xsl:template match="ns2:UserId">
  <ns2:Details>
   <xsl:copy-of select=
    "../node()
          [not(self::ns2:UserId
                 [not(generate-id()=generate-id(current()))])
          ]"/>
  </ns2:Details>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document (containing redundant ns2:UserId elements):

<ns2:Details xmlns:ns2="ns">
    <ns2:var1>AA0511201143</ns2:var1>
    <ns2:var2>PARCEL</ns2:var2>
    <ns2:var3>04/04/2011</ns2:var3>
    <ns2:var4>Organization</ns2:var4>
    <ns2:UserId>46</ns2:UserId>
    <ns2:UserId>237</ns2:UserId>
    <ns2:UserId>46</ns2:UserId>
</ns2:Details>

produces exactly the wanted, correct result:

<ns2:Details xmlns:ns2="ns">
   <ns2:var1>AA0511201143</ns2:var1>
   <ns2:var2>PARCEL</ns2:var2>
   <ns2:var3>04/04/2011</ns2:var3>
   <ns2:var4>Organization</ns2:var4>
   <ns2:UserId>46</ns2:UserId>
</ns2:Details>
<ns2:Details xmlns:ns2="ns">
   <ns2:var1>AA0511201143</ns2:var1>
   <ns2:var2>PARCEL</ns2:var2>
   <ns2:var3>04/04/2011</ns2:var3>
   <ns2:var4>Organization</ns2:var4>
   <ns2:UserId>237</ns2:UserId>
</ns2:Details>

Explanation: Muenchian grouping, xsl:copy-of, use of current()

like image 1
Dimitre Novatchev Avatar answered Oct 23 '22 02:10

Dimitre Novatchev