0

I was developing an xsl that converts the input xml to other xml using XSLT as mentioned Below.

Logic: In the input xml, I mention four sub-elements "vehicle_No, vehicle_Model, Description, colour" in "Vehicle". I want to get a result " if "vehicle_No, vehicle_Model" matches with the next "vehicle" then the value in the "description" should become elements and then the output should look like..., Also Muenchian grouping for "Description" when "vehicle_No, vehicle_Model" matches,

Sample O/P: If Matched

<vehicle>
     <car>
          <color>BLACK</color>
          <hood>RED</hood>
     </car>
</vehicle>

If aren't Matched

<vehicle>
     <car>
          <color>BLACK</color>
          <hood>RED</hood>
     </car>
     <cycle>
          <color>violet</color>
     </cycle>
</vehicle>

If in case i get a same value for "description" mentioned in input xml and "vehicle_No, vehicle_Model" aren't matches. Then the o/p should look like

<vehicle>
     <car>
          <color>BLACK</color>
          <hood>RED</hood>
     </car>
     <cycle>
          <color>violet</color>
     </cycle>
</vehicle>
<vehicle>
     <car>
          <color>RED</color>
     </car>
</vehicle>

My Input XML File:

<t>
<Vehicle>
    <vehicle_No>123</vehicle_No>
    <vehicle_Model>Audi</vehicle_Model>
    <Description>car.color</Description>
    <colour>BLACK</colour>
</Vehicle>
<Vehicle>
    <vehicle_No>123</vehicle_No>
    <vehicle_Model>Audi</vehicle_Model>
    <Description>car.hood</Description>
    <colour>RED</colour>
</Vehicle>
<Vehicle>
    <vehicle_No>123</vehicle_No>
    <vehicle_Model>BMW</vehicle_Model>
    <Description>Bus.Brakes</Description>
    <colour>steel</colour>
</Vehicle>
<Vehicle>
    <vehicle_No>123</vehicle_No>
    <vehicle_Model>BMW</vehicle_Model>
    <Description>Bus.steering</Description>
    <colour>black</colour>
</Vehicle>
<Vehicle>
    <vehicle_No>234</vehicle_No>
    <vehicle_Model>benz</vehicle_Model>
    <Description>cycle.color</Description>
    <colour>violet</colour>
</Vehicle>
<Vehicle>
    <vehicle_No>345</vehicle_No>
    <vehicle_Model>nissan</vehicle_Model>
    <Description>car.color</Description>
    <colour>RED</colour>
</Vehicle>
</t>

Expected Output in XML:

<t>
<Vehicle>
    <car>
        <color>BLACK</color>
        <hood>RED</hood>
    </car>
    <Bus>
        <Brakes>steel</Brakes>
        <Steering>black</Steering>
    </Bus>
    <cycle>
        <color>violet</color>
    </cycle>
</Vehicle>
<vehicle>
    <car>
        <color>RED</color>
    </car>
</vehicle>
</t>

Please let me know if Question was unclear.

4

1 に答える 1

1

This XSLT 1.0 style-sheet ...

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

<xsl:key name="vehicle-by-number" match="Vehicle" use="vehicle_No" /> 
<xsl:key name="vehicle-by-form"   match="Vehicle" use="
  concat( vehicle_No, '-', substring-before(Description,'.'))" /> 

<xsl:template match="/*">
 <xsl:copy>
  <xsl:apply-templates select="Vehicle[
   generate-id(.) = generate-id(key('vehicle-by-number',vehicle_No)[1])]"
   mode="vehicle-group" />
 </xsl:copy>
</xsl:template>

<xsl:template match="Vehicle" mode="vehicle-group">
 <xsl:copy>
   <xsl:apply-templates select="key('vehicle-by-number',vehicle_No)
    [generate-id(.) = generate-id(key('vehicle-by-form',
      concat( vehicle_No, '-', substring-before(Description,'.')))[1])]"
    mode="form-group" />
 </xsl:copy>
</xsl:template>

<xsl:template match="Vehicle" mode="form-group">
 <xsl:element name="{substring-before(Description,'.')}">
   <xsl:for-each select="key('vehicle-by-form',concat( vehicle_No, '-', substring-before(Description,'.')))">
    <xsl:element name="{substring-after(Description,'.')}">
      <xsl:value-of select="colour" /> 
    </xsl:element>   
   </xsl:for-each>   
 </xsl:element>
</xsl:template>

</xsl:stylesheet>

... when applied to your sample input, will produce ...

<?xml version="1.0" encoding="utf-8"?>
<t>
  <Vehicle>
    <car>
      <color>BLACK</color>
      <hood>RED</hood>
    </car>
    <Bus>
      <Brakes>steel</Brakes>
      <steering>black</steering>
    </Bus>
  </Vehicle>
  <Vehicle>
    <cycle>
      <color>violet</color>
    </cycle>
  </Vehicle>
  <Vehicle>
    <car>
      <color>RED</color>
    </car>
  </Vehicle>
</t>

While this is not an exact match for your listed expected output, I believe that the difference is due to an error in your listed expected output. I refer in particular to the position of the node whose value is 'violet'.

Explanation

This stylesheet uses 2 levels of muenchian grouping. The first level is straight-forward enough. It groups all the vehicles together, under one output vehicle element which have the same vehicle number. In most examples in SO of muenchian, a for-each is used to iterate through group members, whereas I have used an apply-templates. It amounts to the same thing.

I have a second key (vehicle-by-form), for the second level of grouping. By 'form', I mean car, bus, cycle etc. This key groups on both vehicle number and form. Vehicles are grouped under an output node named after the form. And within this inner group, we emit nodes like steel, which are members of the group.

于 2012-07-08T13:58:12.197 に答える