1

Is it possible to get such transformation:

Source XML:

<Item>
  <stockcode>XXX1</stockcode>
  <vehicle>Bentley</vehicle>
  <model>Continental GT (2006-)</model>
  <model>Continental Flying Spur (2006-)</model>
  <width>9</width>
  <wheel_size>20</wheel_size>  
  <offset>40</offset>
  <bolt_pattermn>5x112</bolt_pattermn>
  <brand>AEZ</brand>
  <Velg_ID>AEZ Myta</Velg_ID>
  <kit1>DK-ZJAE x1</kit1>
</Item>

Target XML:

<Item>
  <stockcode>XXX1</stockcode>
  <vehicle>Bentley</vehicle>
  <model>Continental GT (2006-)</model>
  <width>9</width>
  <wheel_size>20</wheel_size>    
  <offset>40</offset>
  <bolt_pattermn>5x112</bolt_pattermn>
  <brand>AEZ</brand>
  <Velg_ID>AEZ Myta</Velg_ID>
  <kit1>DK-ZJAE x1</kit1>
  <qty_available>8.00000000</qty_available>
  <price>174.00</price>
  <picture>41010</picture>
  <pkpcena>195.4999</pkpcena>
</Item>
<Item>
  <stockcode>XXX1</stockcode>
  <vehicle>Bentley</vehicle>
  <model>Continental Flying Spur (2006-)</model>
</Item>

In source XML there is X elements for 1 node which have to be divided into 1 element for X nodes. Target XML can have all elements as in source or just the element <vehicle> and <model>!

If Yes - can somebody give a hint? ;-)

Thank You!

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
Mole_LR
  • 69
  • 1
  • 10

2 Answers2

1

This would do it:

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

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates select="//model" mode="split" />
    </root>
  </xsl:template>

  <xsl:template match="model" mode="split">
    <xsl:apply-templates select="..">
      <xsl:with-param name="currentModel" select="." />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="Item">
    <xsl:param name="currentModel" />

    <xsl:copy>
      <xsl:apply-templates
         select="@* | node()[not(self::model)] | $currentModel" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

When applied to your sample input, this produces:

<root>
  <Item>
    <stockcode>XXX1</stockcode>
    <vehicle>Bentley</vehicle>
    <model>Continental GT (2006-)</model>
    <width>9</width>
    <wheel_size>20</wheel_size>
    <offset>40</offset>
    <bolt_pattermn>5x112</bolt_pattermn>
    <brand>AEZ</brand>
    <Velg_ID>AEZ Myta</Velg_ID>
    <kit1>DK-ZJAE x1</kit1>
  </Item>
  <Item>
    <stockcode>XXX1</stockcode>
    <vehicle>Bentley</vehicle>
    <model>Continental Flying Spur (2006-)</model>
    <width>9</width>
    <wheel_size>20</wheel_size>
    <offset>40</offset>
    <bolt_pattermn>5x112</bolt_pattermn>
    <brand>AEZ</brand>
    <Velg_ID>AEZ Myta</Velg_ID>
    <kit1>DK-ZJAE x1</kit1>
  </Item>
</root>

Here's an implementation where I've shortened my above approach, with some pointers from Dimitre's technique:

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

  <xsl:template match="model">
    <xsl:apply-templates select=".." mode="gen">
      <xsl:with-param name="currentModel" select="." />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="@* | node()" mode="gen">
    <xsl:param name="currentModel" select="/.." />

    <xsl:copy>
      <xsl:apply-templates
         select="@* | node()[not(self::model)] | $currentModel" 
         mode="gen" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="text()" />
</xsl:stylesheet>
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Thank You, very much! it works... It was more than "just a hint"! ;-D – Mole_LR Mar 10 '13 at 16:28
  • Glad to help. I've just made a small modification that makes the XSLT a little cleaner and avoids the use of `generate-id()`. And don't forget to mark this answer as accepted. Thanks! :) – JLRishe Mar 10 '13 at 16:43
  • JLRishe, Your solutions still are only working with 'model' ... What if the user specifies the name of the repeating element? – Dimitre Novatchev Mar 10 '13 at 20:09
  • JLRishe, Also, you need to remove the text saying: "uses some pointers from Dimitre's technique but can handle ``s with more than two ``s and documents with more than one ``:" -- this misleads the reader into believing that my answer has the alleged shortcomings, which it doesn't actually have. – Dimitre Novatchev Mar 10 '13 at 20:25
  • I've removed the text you referred to now that it's not true anymore. I don't think the asker is looking for the degree of genericity you're referring to, so I'll leave my answers as they are now. – JLRishe Mar 11 '13 at 03:02
0

I. This transformation:

<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:template match="text()"/>

 <xsl:template match="model">
  <xsl:apply-templates select=".." mode="gen">
   <xsl:with-param name="pInclude" select="."/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="node()|@*" mode="gen">
  <xsl:param name="pInclude" select="/.."/>
      <xsl:copy>
       <xsl:apply-templates mode="gen" select=
        "node()[not(name()=name($pInclude)) or count(.|$pInclude)=1]|@*" >
        <xsl:with-param name="pInclude" select="$pInclude"/>
       </xsl:apply-templates>
      </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document (the provided one with a third model added and more than one Item element):

<t>
    <Item>
        <stockcode>XXX1</stockcode>
        <vehicle>Bentley</vehicle>
        <model>Continental GT (2006-)</model>
        <model>Continental Flying Spur (2006-)</model>
        <model>Galactic Flying Spur (2006-)</model>
        <width>9</width>
        <wheel_size>20</wheel_size>
        <offset>40</offset>
        <bolt_pattermn>5x112</bolt_pattermn>
        <brand>AEZ</brand>
        <Velg_ID>AEZ Myta</Velg_ID>
        <kit1>DK-ZJAE x1</kit1>
    </Item>
    <Item>
        <stockcode>XXX1</stockcode>
        <vehicle>Bentley</vehicle>
        <model>XXX Continental GT (2006-)</model>
        <model>YYY Continental Flying Spur (2006-)</model>
        <model>ZZZ Galactic Flying Spur (2006-)</model>
        <width>9</width>
        <wheel_size>20</wheel_size>
        <offset>40</offset>
        <bolt_pattermn>5x112</bolt_pattermn>
        <brand>AEZ</brand>
        <Velg_ID>AEZ Myta</Velg_ID>
        <kit1>DK-ZJAE x1</kit1>
    </Item>
</t>

produces the wanted, correct result:

<Item>
   <stockcode>XXX1</stockcode>
   <vehicle>Bentley</vehicle>
   <model>Continental GT (2006-)</model>
   <width>9</width>
   <wheel_size>20</wheel_size>
   <offset>40</offset>
   <bolt_pattermn>5x112</bolt_pattermn>
   <brand>AEZ</brand>
   <Velg_ID>AEZ Myta</Velg_ID>
   <kit1>DK-ZJAE x1</kit1>
</Item>
<Item>
   <stockcode>XXX1</stockcode>
   <vehicle>Bentley</vehicle>
   <model>Continental Flying Spur (2006-)</model>
   <width>9</width>
   <wheel_size>20</wheel_size>
   <offset>40</offset>
   <bolt_pattermn>5x112</bolt_pattermn>
   <brand>AEZ</brand>
   <Velg_ID>AEZ Myta</Velg_ID>
   <kit1>DK-ZJAE x1</kit1>
</Item>
<Item>
   <stockcode>XXX1</stockcode>
   <vehicle>Bentley</vehicle>
   <model>Galactic Flying Spur (2006-)</model>
   <width>9</width>
   <wheel_size>20</wheel_size>
   <offset>40</offset>
   <bolt_pattermn>5x112</bolt_pattermn>
   <brand>AEZ</brand>
   <Velg_ID>AEZ Myta</Velg_ID>
   <kit1>DK-ZJAE x1</kit1>
</Item>
<Item>
   <stockcode>XXX1</stockcode>
   <vehicle>Bentley</vehicle>
   <model>XXX Continental GT (2006-)</model>
   <width>9</width>
   <wheel_size>20</wheel_size>
   <offset>40</offset>
   <bolt_pattermn>5x112</bolt_pattermn>
   <brand>AEZ</brand>
   <Velg_ID>AEZ Myta</Velg_ID>
   <kit1>DK-ZJAE x1</kit1>
</Item>
<Item>
   <stockcode>XXX1</stockcode>
   <vehicle>Bentley</vehicle>
   <model>YYY Continental Flying Spur (2006-)</model>
   <width>9</width>
   <wheel_size>20</wheel_size>
   <offset>40</offset>
   <bolt_pattermn>5x112</bolt_pattermn>
   <brand>AEZ</brand>
   <Velg_ID>AEZ Myta</Velg_ID>
   <kit1>DK-ZJAE x1</kit1>
</Item>
<Item>
   <stockcode>XXX1</stockcode>
   <vehicle>Bentley</vehicle>
   <model>ZZZ Galactic Flying Spur (2006-)</model>
   <width>9</width>
   <wheel_size>20</wheel_size>
   <offset>40</offset>
   <bolt_pattermn>5x112</bolt_pattermn>
   <brand>AEZ</brand>
   <Velg_ID>AEZ Myta</Velg_ID>
   <kit1>DK-ZJAE x1</kit1>
</Item>

II. A more generic, and still short transformation, where the element name on which to split is passed as an (external) parameter:

<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:param name="pName" select="'model'"/>

 <xsl:template match="*">
  <xsl:apply-templates select="parent::*[$pName = name(current())]" mode="gen">
   <xsl:with-param name="pInclude" select="."/>
  </xsl:apply-templates>
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="node()|@*" mode="gen">
  <xsl:param name="pInclude" select="/.."/>

      <xsl:copy>
       <xsl:apply-templates mode="gen" select=
       "node()[not(name()=name($pInclude)) or count(.|$pInclude)=1]|@*" >
        <xsl:with-param name="pInclude" select="$pInclude"/>
       </xsl:apply-templates>
      </xsl:copy>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

III. The most generic solution to a generic problem of this kind:

See this answer: https://stackoverflow.com/a/8597577/36305

Community
  • 1
  • 1
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • It's not an added requirement. OP stated: "In source XML there is X elements for 1 node which have to be divided into 1 element for X nodes." And besides which, as you told me some time ago, it's important to anticipate what OP could conceivably need, and not just solve the simplified example. A view of the asker's past questions reveals similar XML with several ``s for a single ``. – JLRishe Mar 10 '13 at 18:58
  • @JLRishe, Yes, but the title of the question was "Spilt 2 elements in 1 node into 2 elements and 2 nodes" ... I edited the title so now it isn't misleading. Thanks for clarifying this. I am a little bit sleepy this first Summer Date Time Savings Sunday morning (hmm,... noon!) but even in this situation still can produce significantly shorter and more generic solutions :) – Dimitre Novatchev Mar 10 '13 at 19:10