-3

This is something related to XSL transformations. input.xml

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/x/transform.xsl"?>
<!-- input file root node-->
<message>           
    <header>
     <!--Many descendents will be there -->
    </header>
    <body>
     <!-- some other several elements will be there-->
      <TaskList>
        <TaskItem>
          <DataPoint>
            <Name>software.prog_name</Name>
            <Target>JAVA</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.prog_rev</Name>
            <Target>1</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.sw_product_id</Name>
            <Target>1000</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.limits_file_name</Name>
            <Target>limits.txt</Target>
          </DataPoint>
          <DataPoint>
            <Name>software.limits_file_rev</Name>
            <Target>2</Target>
          </DataPoint>
          <DataPoint>
            <Name>hw_exp.class</Name>
            <Target>Car</Target>    
          </DataPoint>
          <DataPoint>
            <Name>hw_exp.type</Name>
            <Target>B</Target>
          </DataPoint>
          <DataPoint>
            <Name>hw_exp.rev</Name>
            <Target>32</Target>
          </DataPoint>
          <DataPoint>
            <Name>prompt_id</Name>
            <Target>100</Target>
          </DataPoint>
        </TaskItem>
        <AutomationParam>
          <Profile>Profile 1</Profile>
          <SubGroup>1</SubGroup>
          <Name>software.prog_name</Name>
          <Value>JAVA</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>1</SubGroup>
         <Name>software.sw_product_id</Name>
         <Value>1000</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>2</SubGroup>
         <Name>hw_exp.class</Name>
         <Value>Animal</Value>  
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>2</SubGroup>
         <Name>hw_exp.type</Name>
         <Value>B</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>3</SubGroup>
         <Name>hw_exp.class</Name>
         <Value>Flight</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>3</SubGroup>
         <Name>hw_exp.type</Name>
         <Value>E</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 1</Profile>
         <SubGroup>3</SubGroup>
         <Name>hw_exp.rev</Name>
         <Value>1</Value>
       </AutomationParam>
       <AutomationParam>
         <Profile>Profile 2</Profile>
         <SubGroup>1</SubGroup>
         <Name>software.sw_product_id</Name>
         <Value>1000</Value>
       </AutomationParam>    
     </TaskList>
   </body>
 </message>

After applying XSL tranform on input.xml the generated file be output.xml output.xml (It should be like this)

<?xml version="1.0" encoding="utf-8"?>
<!-- output file root node-->
<text>    
  <header>
    <!--All descendents will/should be copied as it is-->
  </header>
  <body>
    <sub_body>
     <!-- All such several elements from input.xml will/should be there-->
     <test_profile>
       <software>
         <prog_name>JAVA</prog_name>
         <prog_rev>1</prog_rev>
         <sw_product_id>1000</sw_product_id>
         <limits_file_name>limits.txt</limits_file_name>
         <limits_file_rev>2</limits_file_rev>
       </software>
       <hw_exp>
         <class>Car</class>
         <type>B</type>
         <rev>32</rev>
       </hw_exp>
       <prompt_id>100</prompt_id>
     </test_profile>
     <test_profile>
       <software>
         <prog_name>JAVA</prog_name>
         <sw_product_id>1000</sw_product_id>
       </software>
       <hw_exp>
         <class>Animal</class>
         <type>B</type>
       </hw_exp>
       <hw_exp>
         <class>Flight</class>
         <type>E</type>
         <rev>1</rev>
       </hw_exp>
     </test_profile>
     <test_profile>
       <software>
         <sw_product_id>1000</sw_product_id>
       </software>
     </test_profile>
   </sub_body>
 </body>

Please someone help me in achieving this, that would be a great help. I need XSL 1.0 (but not 2.x +) code.

Mapping Rules: a) one <test_profile> record in output.xml should be mapped to entire TaskList.TaskItem in input.xml b) you are seeing extra two <test_profile> elements [records] in output.xml as you are seeing <profile> element's values in input.xml as Profile 1 and Profile 2 [which means all Profile 1 related things should go into one different <test_profile> and all Profile 2 related things should go into another different <test_profile>. c) <header> element and its whole content (can be several descendents) should be copied as it is. d) <DataPoint> and <AutomationParams> are not fixed number of elements. These things can be 0 [either nothing] to infinity [many] which means all should be done dynamically and moreover there can be 0 to many profiles [i.e Profile 1, Profile 2, Profile 3, .. and it can be any string like jack, jill etc..,] for AutomationParams

Note: Think that this input.xml file is being populated dynamically based on the records in the database.

  • Hi, If the question is not clear please comment here, I'll try to elaborate it... but I am deliberately looking for the logical idea because it is little tricky.. – Haneesh Pepala Jul 04 '12 at 04:52
  • Your question isn't really so much a question as a can-you-do-this-whole-thing-for-me. Can you show us some of your attempts? Are you absolutely unfamiliar with XSLT? If so, the internet is FILLED with great tutorials. W3Schools gets a lot of flak, but I still feel like it's the best place to start: http://www.w3schools.com/xsl/ . Try that and come back if you have any other questions! – Sandy Gifford Jul 04 '12 at 14:03
  • @SandyGifford I tried every basic thing that I can do. Actually I am very new to XSL. I tried to do the coding upto some extent. I got stuck at prompt_id value for //DataPoint.Name. It doesn't have '.' in it. So It became little complicated for me to work with templates. But whoever keeps the answer I am seeking explanation too. I know this can be done by using two pass transform but I didn't get any solution/idea to achieve this (But I can say that this is tricky and need to understand the question properly) – Haneesh Pepala Jul 04 '12 at 17:38
  • It would still be good if you could just post what XSLT you have so far, so we could help you from where you are. – Sandy Gifford Jul 04 '12 at 17:43
  • You need to explain the rules of transformation. These CANNOT be inferred simply from your current sample documents. For example, there are 3 output test_profile nodes. There is no apparent rule about where the last two come from. Can there be more than 3 test_profile nodes? If so, what does it depend on? – Sean B. Durkin Jul 04 '12 at 23:48
  • Ok. @SeanB.Durkin I just now ran your XSL using xalan on input.xml and the pseudo output I got is: I got one within another but I need all of the elements to be different [There should be no child/descendent for any parent ] bcoz all these are individual records. – Haneesh Pepala Jul 05 '12 at 04:27
  • @SeanB.Durkin Coming to your question: This is how mapping should be: – Haneesh Pepala Jul 05 '12 at 04:32
  • Mapping Rules: a) one record in output.xml should be mapped to entire TaskList.TaskItem in input.xml b) you are seeing extra two elements [records] in output.xml as you are seeing element's values in input.xml as Profile 1 and Profile 2 [which means all Profile 1 related things should go into one different and all Profile 2 related things should go into another different . – Haneesh Pepala Jul 05 '12 at 04:40
  • I hope this explanation helps but @SeanB.Durkin Thanks for your effort atleast in trying to get the solution. I am expecting a definite answer from you. Because you got that doubt regarding as you tried it. Again thank you for helping me in trying to get the solution for me. – Haneesh Pepala Jul 05 '12 at 04:51
  • So there are exactly 2 "profiles", 1 & 2? Never more, or less? Or is the number of profiles arbitary? Also some of the AutomationParam nodes map to software node, but others map to a hw_exp node. What is the discriminator for which type of output node (software/hw_exp) the AutomationParam maps to? Also, what determines how many hw_exp nodes there will be per test_profile? – Sean B. Durkin Jul 05 '12 at 05:54
  • In this input.xml there are only 2 profiles i.e. Profile 1 and Profile 2 but there can be many so I don't want the coding to be done assuming that there will be only two profiles. There can be many Profiles or no Profiles at all which means there will be no AutomationParam tag (so it is arbitary). – Haneesh Pepala Jul 05 '12 at 15:20
  • Yes some of the things map to software and hw_exp. FYI in AutomationParam there will be only one software record (If AutomationParam element is there then there will be one software record definitely) but hw_exp can be 0 to many. All these things and records should be mapped accordingly by seeing and concentrating more on and . Here says how to map i.e. to which and says grouping of the things like software, hw_exp records. For example: hw_exp.class --> 1 – Haneesh Pepala Jul 05 '12 at 15:39
  • and hw_exp.class --> 2 which implies there are 2 hw_exp records in (assuming that both element's values are same for the above specified two elements which means all these different records are under same ) – Haneesh Pepala Jul 05 '12 at 15:48
  • @SeanB.Durkin Have you seen my update? Are you clear regarding the question..? – Haneesh Pepala Jul 06 '12 at 03:02
  • It seems pretty good though. But there is a small mistake in the output. I don't need the same root element in the output.xml [Infact we can hardcode that root element for output.xml but that element is and should be different than that of the input.xml's root node.] And one more thing: thats very important: If there is no record in the input.xml for any thing like software, hw_exp and their sub elements like sw_product_id then I should not get any element related to them (even empty element too) in the output.xml – Haneesh Pepala Jul 06 '12 at 18:52
  • In the logic can you make sure to compare the values by the whole string instead of the numbers. Because it can be like this:Jack Jill etc.., so i need the comparison for the whole string instead of the substrings. – Haneesh Pepala Jul 06 '12 at 19:37
  • @SeanB.Durkin All these things made my mind blowing. Thats the reason I approached stackoverflow. – Haneesh Pepala Jul 06 '12 at 19:41
  • I don't have enough reputation to say that your updated answer is useful (otherwise I would have said that your answer is useful). – Haneesh Pepala Jul 07 '12 at 06:18
  • @SeanB.Durkin Please help me in coding this. Have you seen my updated question? – Haneesh Pepala Jul 08 '12 at 21:04

1 Answers1

2

This is not a complete solution. Your question is far too unclear to allow that. This XSLT 1.0 style-sheet may provide a helpful indication for you to provide your own solution.

This style-sheet ...

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

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

<xsl:template match="body">
 <xsl:copy>
  <sub_body>
   <test_profile>
    <xsl:apply-templates select="TaskList/TaskItem"/>
   </test_profile>
  </sub_body>
 </xsl:copy>
</xsl:template>

<xsl:template match="TaskItem">
 <test_profile>
  <software>
   <prog_name><xsl:value-of select="DataPoint[Name='software.prog_name']/Target" /></prog_name>
    <prog_rev><xsl:value-of select="DataPoint[Name='software.prog_re']/Target"/></prog_rev>
   <sw_product_id><xsl:value-of select="DataPoint[Name='software.sw_product_id']/Target"/></sw_product_id>
   <limits_file_name><xsl:value-of select="DataPoint[Name='software.limits_file_name']/Target"/></limits_file_name>
   <limits_file_rev><xsl:value-of select="DataPoint[Name='software.limits_file_rev']/Target" /></limits_file_rev>
  </software>
  <hw_exp>
   <class><xsl:value-of select="DataPoint[Name='hw_exp.class']/Target" /></class>
   <type><xsl:value-of select="DataPoint[Name='hw_exp.type']/Target" /></type>
   <rev><xsl:value-of select="DataPoint[Name='hw_exp.rev']/Target" /></rev>
  </hw_exp>
  <prompt_id><xsl:value-of select="DataPoint[Name='prompt_id']/Target" /></prompt_id>
 </test_profile>
</xsl:template>

</xsl:stylesheet>

... when applied to your sample input will produce the first test_profile node of your required output. You have not explained the rules of transformation in relation to the other two test_profile nodes.


UPDATE

This style-sheet will use muenchian grouping and run-time computed element names to produce the additional test_profile nodes and organise the hw_exp nodes by subgroup.

This style-sheet ...

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

<xsl:key name="param-by-profile" match="AutomationParam" use="substring-after( Profile, 'Profile ')" />
<xsl:key name="subgroup" match="AutomationParam" use="SubGroup" />

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

<xsl:template match="body">
 <xsl:copy>
  <sub_body>
    <xsl:apply-templates select="TaskList/TaskItem"/>
    <xsl:for-each select="TaskList/AutomationParam[
      generate-id(.) = generate-id( key('param-by-profile', substring-after( Profile, 'Profile '))[1])
      ]">
        <xsl:sort data-type="number" select="substring-after( Profile, 'Profile ')" />
        <xsl:call-template name="profile-from-param">
          <xsl:with-param name="automations" select="key('param-by-profile',substring-after( Profile, 'Profile '))" />
        </xsl:call-template>  
    </xsl:for-each>
  </sub_body>
 </xsl:copy>
</xsl:template>

<xsl:template match="TaskItem">
 <test_profile>
  <software>
   <prog_name><xsl:value-of select="DataPoint[Name='software.prog_name']/Target" /></prog_name>    
   <prog_rev><xsl:value-of select="DataPoint[Name='software.prog_rev']/Target"/></prog_rev>
   <sw_product_id><xsl:value-of select="DataPoint[Name='software.sw_product_id']/Target"/></sw_product_id>
   <limits_file_name><xsl:value-of select="DataPoint[Name='software.limits_file_name']/Target"/></limits_file_name>
   <limits_file_rev><xsl:value-of select="DataPoint[Name='software.limits_file_rev']/Target" /></limits_file_rev>
  </software>
  <hw_exp>
   <class><xsl:value-of select="DataPoint[Name='hw_exp.class']/Target" /></class>
   <type><xsl:value-of select="DataPoint[Name='hw_exp.type']/Target" /></type>
   <rev><xsl:value-of select="DataPoint[Name='hw_exp.rev']/Target" /></rev>
  </hw_exp>
  <prompt_id><xsl:value-of select="DataPoint[Name='prompt_id']/Target" /></prompt_id>
 </test_profile>
</xsl:template>

<xsl:template name="profile-from-param">
 <xsl:param name="automations" />
 <test_profile>
  <software>
   <xsl:apply-templates select="$automations[SubGroup=1]" /> 
  </software>
  <xsl:for-each select="$automations
    [generate-id(.) = generate-id( key('subgroup', SubGroup)[1])]
    [SubGroup >= 2]
    ">
    <xsl:sort data-type="number" select="SubGroup" />
    <xsl:call-template name="hw-group">
      <xsl:with-param name="automations" select="key('subgroup', SubGroup)" />
    </xsl:call-template>  
   </xsl:for-each>    
 </test_profile>  
</xsl:template>  

<xsl:template name="hw-group">
  <xsl:param name="automations" />
  <hw_exp>
   <xsl:apply-templates select="$automations" /> 
  </hw_exp>
</xsl:template>  

<xsl:template match="AutomationParam">
 <xsl:element name="{substring-after(Name,'.')}"> 
  <xsl:value-of select="Value" />
 </xsl:element>
</xsl:template>

</xsl:stylesheet>

... when applied to the provided sample input, will produce this document ...

<?xml version="1.0" encoding="utf-8"?>
<message>           
 <header>
     <!--Many descendents will be there -->
 </header>
 <body>
  <sub_body>

   <test_profile>
    <software>
     <prog_name>JAVA</prog_name>
     <prog_rev>1</prog_rev>
     <sw_product_id>1000</sw_product_id>
     <limits_file_name>limits.txt</limits_file_name>
     <limits_file_rev>2</limits_file_rev>
    </software>
    <hw_exp>
     <class>Car</class>
     <type>B</type>
     <rev>32</rev>
    </hw_exp>
    <prompt_id>100</prompt_id>
   </test_profile>

   <test_profile>
    <software>
     <prog_name>JAVA</prog_name>
     <sw_product_id>1000</sw_product_id>
    </software>
    <hw_exp>
     <class>Animal</class>
     <type>B</type>
    </hw_exp>
    <hw_exp>
     <class>Flight</class>
     <type>E</type>
     <rev>1</rev></hw_exp>
    </test_profile>

    <test_profile>
     <software>
      <sw_product_id>1000</sw_product_id>
     </software>
    </test_profile>

  </sub_body>
 </body>
 </message>
Sean B. Durkin
  • 12,659
  • 1
  • 36
  • 65
  • Sean, All DataPoint related things should go into one single test profile. But related things will go into multiple test profiles based on the tag and in that individual there can be several records, so all these software related things are identified by tag. – Haneesh Pepala Jul 04 '12 at 17:31
  • If you are not clear still regarding the question please feel free to ask. Everything related to my Q can be analysed by using the values in the elements in the input.xml and output.xml – Haneesh Pepala Jul 04 '12 at 17:45
  • I thought I would have got some answer from @Dimitre Novatchev within short period of time as I saw somewhat similar question answered by him but I came to know that my Q itself is not clear. But now I think the Question is clear. – Haneesh Pepala Jul 05 '12 at 05:06
  • Thanks for your effort Sean. Your answer gave me a way to solve the problem eventhough your answer is not complete. – Haneesh Pepala Nov 29 '12 at 13:41