开发者

XSLT grouping with multiple group collection

I need some help with this XSLT. It is working the way it is suppose to however I have change in requirements ... :-) and I need to modify this to give me the expected output. I'm looking for some guidance and help.

Explanation: I have a source xml like this

<XML>
  <Attributes>
    <Attribute>
    <Name/>
    <Type/>
    <Value/>
    <FromIM/>
    <collection/>
      <Path />
    </Attribute>
</Attributes>
</XML>

In the above xml I need to look at the node "Type" and group them by the type. For example, if I have 5 attribute where Type is common, and 4 attributes where Type is category, and 3 attributes where Type is Complex then group them like this.

<?xml version="1.0" encoding="utf-8"?>
<Data Schema="XML A">
  <Items>
    <Item id="" shortname="FT123" longname="FT123" categorypath="FamilyName//DepartmentName//GroupName" type="Product">
      <Attributes type="common">
        <Attr name="common 1" value="1" path=""/>
        <Attr name="common 2" value="2" path=""/>
        <Attr name="common 3" value="3" path=""/>
        <Attr name="common 4" value="4" path=""/>
        <Attr name="common 5" value="4" path=""/>
        <Collection id="" name="Collection" path="">
          <Complex>
            <Attr name="UPC" value="Testing" valueKey="0" />
            <Attr name="Color" value="Yellow"  valueKey="0"/>
            <Attr name="Size" value="10"  valueKey="0"/>
          </Complex>
        </Collection>
      </Attributes>
      <Attributes type="category">
        <Attr name="category1" value="1" />
        <Attr name="category2" value="2" />
        <Attr name="category3" value="3" />
        <Attr name="category4" value="4" />
      </Attributes>
     </Item>
    </Items>
 </Data>

As you can see from above that I'm group first common & category and creating a group collection for Complex under common. This is working fine (Although I'm using Iteration ... :-))

The problem is I'm creating a Complex for only 1 attribute where Name = Collection and it is hard coded. However, the new requirement is that I have create a complex collection for another attribute where name=Cost.

This is where I'm having problem. How can I do this. Below are the sample source and output xml and XSLT. Thanks in Advance.

Source XML:

<?xml version="1.0" encoding="Windows-1252"?>
<XML>
  <Attributes>
    <Attribute>
      <Name>FamilyName</Name>
      <Type>common</Type>
      <Value>Footwear</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>DepartmentName</Name>
      <Type>common</Type>
      <Value>Footwear</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>GroupName</Name>
      <Type>common</Type>
      <Value>Men's Boots</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Buyer ID</Name>
      <Type>common</Type>
      <Value>Lee</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Enviornment</Name>
      <Type>common</Type>
      <Value>Dev</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Retail</Name>
      <Type>common</Type>
      <Value></Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Gender</Name>
      <Type>category</Type>
      <Value>M</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Cost</Name>
      <Type>Complex</Type>
      <Value>20.00</Value>
      <FromIM>yes</FromIM>
      <collection>Y</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Collection</Name>
      <Type>Complex</Type>
      <Value>ing</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>UPC</Name>
      <Type>Complex</Type>
      <Value>Testing</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Color</Name>
      <Type>Complex</Type>
      <Value>Yellow</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Size</Name>
      <Type>Complex</Type>
      <Value>10</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Style</Name>
      <Type>Complex</Type>
      <Value>MA</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>UPC</Name>
      <Type>Complex</Type>
      <Value>24a</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Color</Name>
      <Type>Complex</Type>
      <Value>Green</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Size</Name>
      <Type>Complex</Type>
      <Value>22</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
    <Attribute>
      <Name>Style</Name>
      <Type>Complex</Type>
      <Value>AM</Value>
      <FromIM>no</FromIM>
      <collection>N</collection>
      <Path />
    </Attribute>
  </Attributes>
</XML>

Expected Output: I need 2 collection nodes also in date I need to put current date. Note in the Collection Node I can have multiple Complex nodes. However, in the Cost I will have only 1 Complex node.

<?xml version="1.0" encoding="utf-8"?>
<Data Schema="XML A">
  <Items>
    <Item id="" shortname="FT123" longname="FT123" sku="FT123" action="ADD" categorypath="FamilyName//DepartmentName//GroupName" type="Product">
      <Attributes type="common">
        <Attr name="Buyer ID" value="Lee" path="" action="ADD" />
        <Attr name="Enviornment" value="Dev" path="" action="ADD" />
        <Attr name="Retail" value="" path="" action="ADD" />
        <Collection id="" name="Collection" path="">
          <Complex>
            <Attr name="UPC" value="Testing" valueKey="0" />
            <Attr name="Color" value="Yellow"  valueKey="0"/>
            <Attr name="Size" value="10"  valueKey="0"/>
            <Attr name="Style" value="MA"  valueKey="0"/>
          </Complex>
          <Complex>
            <Attr name="UPC" value="24a"  valueKey="0"/>
            <Attr name="Color" value="Green"  valueKey="0"/>
            <Attr name="Size" value="22"  valueKey="0"/>
            <Attr name="Style" value="AM"  valueKey="0"/>
          </Complex>
        </Collection>
        <Collection id="" name="Cost" path="">
          <Complex>
            <Attr name="Cost" value="22" valueKey="0" />
            <Attr name="Date" value=""  valueKey="0"/>
          </Complex>
        </Collection>
      </Attributes>
      <Attributes type="category">
        <Attr name="Gender" value="M" />
      </Attributes>
    </Item>
  </Items>
</Data>

XSLT: Updated based on Michael's comment

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="type" match="Attribute" use="Type"/>
  <xsl:template match="/">
    <Data Schema="XML A">
      <Items>
        <Item>
          <xsl:variable name="fileName" select="XML/Attributes/Attribute[Name = 'PIFileNumber']/Value"/>

          <xsl:attribute name="id"></xsl:attribute>
          <xsl:attribute name="shortname">
            <xsl:value-of select="$fileName"/>
          </xsl:attribute>
          <xsl:attribute name="longname">
            <xsl:value-of select="$fileName"/>
          </xsl:attribute>

          <xsl:variable name="familyName" select="XML/Attributes/Attribute[Name = 'FamilyName'/id"/>
          <xsl:variable name="deptName" select="XML/Attributes/Attribute[Name = 'DepartmentName']/id"/>
          <xsl:variable name="groupName" select="XML/Attributes/Attribute[Name = 'GroupName']/id"/>
          <xsl:variable name="catPath" select="concat($familyName,'//',$deptName,'//',$groupName)" />

          <xsl:attribute name="categorypath" select="$catPath"/>
          <xsl:attribute name="type">Product</xsl:attribute>
          <xsl:apply-templates select="XML/Attributes/Attribute[generate-id() = generate-id(key('type', Type)[1])]">
            <xsl:sort select="Type" order="descending"/>
          </xsl:apply-templates>
        </Item>
      </Items>
    </Data>
  </xsl:template>
  <xsl:template match="Attribute">
    <xsl:variable name="compType" select="count(/XML/Attributes/Attribute[Type='Complex' and Name!='Collection'])"/>
    <xsl:variable name="colid" select="/XML/Attributes/Attribute[Name = 'Collection']/id"/>
    <xsl:variable name="colname" select="/XML/Attributes/Attribute[Name = 'Collection']/Name"/>
    <xsl:variable name="colpath" select="/XML/Attributes/Attribute[Name = 'Collection']/Path"/>

    <xsl:if test="Type!='Complex'">
      <Attributes type="{Type}">
        <xsl:apply-templates select="key('type',Type)" mode="out"/>
        <xsl:if test="Type='common'">
          <Collection id="{$colid}" name="{$colname}" path="{$colpath}" action="ADD">
            <xsl:choose>
              <xsl:when test="$compType > 0">
                <xsl:call-template name="for.loop">
                  <xsl:with-param name="i">1</xsl:with-param>
                  <xsl:with-param name="count" select="count(/XML/Attributes/Attribute[Type='Complex' and Name='UPC'])" />
                </xsl:call-template>
              </xsl:when>
              <xsl:otherwise>
                <Complex refId="0">
                  <MaskValue />
                  <Attr id="" name="UPC" value="" valueKey="0"/>
                  <xsl:choose>
                    <xsl:when test="count(/XML/Attributes/Attribute[Name = 'Color']) > 0">
                      <Attr id="{//Attribute[Name = 'Color']/id}" name="Color" value="{//Attribute[Name = 'Color']/Value}" valueKey="0"/>
                    </xsl:when>
                    <xsl:otherwise>
                      <Attr id="" name="Color" value="Default" valueKey="0"/>
                    </xsl:otherwise>
                  </xsl:choose>
                  <xsl:choose>
                    <xsl:when test="count(/XML/Attributes/Attribute[Name = 'Size']) > 0">
                      <Attr id="{//Attribute[Name = 'Size']/id}" name="Color" value="{//Attribute[Name = 'Size']/Value}" valueKey="0"/>
                    </xsl:when>
                    <xsl:otherwise>
                      <Attr id="" name="Size" value="Default" valueKey="0"/>
                    </xsl:otherwise>
                  </xsl:choose>
                  <Attr id="" name="Style" value="" valueKey="0"/>
                  <Attr id="" name="Exclude" value="0" valueKey="0"/>
                </Complex>
              </xsl:otherwise>
            </xsl:choose>
          </Collection>
        </xsl:if>
      </Attributes>
    </xsl:if>
  </xsl:template>
  <xsl:template match="Attribute" mode="out">
    <xsl:if test="FromIM = 'yes'">
      <xsl:choose>
        <xsl:when test="collection = 'Y' and Name!='Color' and Name!='Size'">
          <Collection id="" name="{Name}" path="{Path}">
            <Attr value="{Value}" uom="" locale="en_WW"/>
          </Collection>
        </xsl:when>
        <xsl:otherwise>
          <xsl:if test="Name!='FileNumber' and Name!='NotReqInIM' and Name!='Color' and Name!='Size'">
            <Attr id="{id}" name="{Name}" value="{Value}" path="{Path}" action="ADD"   uom="" Locale="en_WW"/>
          </xsl:if>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
  </xsl:template>
  <xsl:template match="Attribute[Type='Complex']" mode="out">
    <xsl:if test="Name!='Collection'">
      <Attr id="{id}" name="{Name}" value="{Value}" valueKey="0"/>
    </xsl:if>
  </xsl:template>


  <!-- this is for loop code -->
  <xsl:template name="for.loop">
    <xsl:param name="i" />
    <xsl:param name="count" />
    <!--begin_: Line_by_Line_Output -->
    <xsl:if test="$i &lt;= $count">
      <xsl:if test="Name!='Collection'">
        <Complex refId="0">
          <MaskValue />
            <Attr id="{(//Attribute[Type='Complex' and Name = 'UPC'])[position() = $i]/id}" name="UPC" value="{(//Attribute[Type='Complex' and Name = 'UPC'])[position() = $i]/Value}" valueKey="0"/>
    <Attr id="{(//Attribute[Type='Complex' and Name = 'Color'])[position() = $i]/id}" name="Color" value="{(//Attribute[Type='Complex' and Name = 'Color'])[position() = $i]/Value}" valueKey="0"/>
    <Attr id="{(//Attribute[Type='Complex' and Name = 'Size'])[position() = $i]/id}" name="Size" value="{(//Attribute[Type='Complex' and Name = 'Size'])[position() = $i]/Value}" valueKey="0"/>
    <Attr id="{(//Attribute[Type='Complex' and Name = 'Style'])[position() = $i]/id}" name="Style" value="{(//Attribute[Type='Complex' and Name = 'Style'])[position() = $i]/Value}" valueKey="0"/>
    <Attr id="0" name="Exclude" value="0" valueKey="0"/>
        </Complex>
      </xsl:if>
    </xsl:if>

    <!--begin_: RepeatTheLoopUntilFinished-->
    <xsl:if test="$i &lt;= $count">
      <xsl:call-template name="for.loop">
        <xsl:with-param name="i">
          <xsl:value-of select="$i + 1"/>
        </xsl:with-param>
        <xsl:with-param name="count">
          <开发者_如何学C;xsl:value-of select="$count"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>

  </xsl:template>
</xsl:stylesheet>


Although far from perfect, here is one stylesheet that will produce the output you wanted. I'm not sure to what degree the attributes of each complex are fixed or the collection are fixed. Let me know if this helps at all.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:key name="type" match="Attribute" use="Type"/>
    <xsl:template match="/">
        <Data Schema="XML A">
            <Items>
                <Item>
                    <xsl:variable name="fileName" select="XML/Attributes/Attribute/Name['PIFileNumber']/Value"/>
                    <xsl:attribute name="id"></xsl:attribute>
                    <xsl:attribute name="shortname">
                        <xsl:value-of select="$fileName"/>
                    </xsl:attribute>
                    <xsl:attribute name="longname">
                        <xsl:value-of select="$fileName"/>
                    </xsl:attribute>
                    <xsl:variable name="familyName" select="XML/Attributes/Attribute[Name='FamilyName']/Value"/>
                    <xsl:variable name="deptName" select="XML/Attributes/Attribute[Name='DepartmentName']/Value"/>
                    <xsl:variable name="groupName" select="XML/Attributes/Attribute[Name='GroupName']/Value"/>
                    <xsl:variable name="catPath" select="concat($familyName,'//',$deptName,'//',$groupName)" />
                    <xsl:attribute name="categorypath">
                        <xsl:value-of select="$catPath"/>
                    </xsl:attribute>
                    <xsl:attribute name="type">Product</xsl:attribute>
                    <xsl:apply-templates select="XML/Attributes/Attribute[generate-id() = generate-id(key('type', Type)[1])]">
                        <xsl:sort select="Type" order="descending"/>
                    </xsl:apply-templates>
                </Item>
            </Items>
        </Data>
    </xsl:template>
    <xsl:template match="Attribute" mode="Collection">
        <Collection id="" name='Collection'>
            <xsl:apply-templates select="../Attribute[Name='Collection']" mode="Coll"/>
        </Collection>
        <Collection id="" name='Cost'>
            <xsl:apply-templates select="../Attribute[Name='Cost']" mode="Cost"/>
        </Collection>
    </xsl:template>
    <xsl:template match="Attribute[Type='Complex']"/>
    <xsl:template match="Attribute[Type != 'Complex']">
        <Attributes type="{Type}">
            <xsl:variable name="Type" select="Type"/>
            <xsl:apply-templates select="../Attribute[Type=$Type]" mode="Attr"/>
            <xsl:if test="Type='common'">
                <xsl:apply-templates select="." mode="Collection"/>
            </xsl:if>
        </Attributes>
    </xsl:template>
    <xsl:template match="Attribute" mode="Coll">
        <xsl:apply-templates select="../Attribute[Name='UPC']" mode="UPC"/>
    </xsl:template>
    <xsl:template match="Attribute" mode="Cost">
        <complex>
            <Attr name="Cost" value="{../Attribute[Name='Cost']/Value}" valueKey="0"/>
            <Attr name="Date" value="" valueKey="0"/>
        </complex>
    </xsl:template>
    <xsl:template match="Attribute" mode="Attr">
        <Attr name="{Name}" value="{Value}" valueKey="0"/>
    </xsl:template>
    <xsl:template match="Attribute" mode="UPC">
        <complex>
            <Attr name="UPC" value="{Value}" valueKey="0"/>
            <Attr name="Color" value="{following::node()[Name='Color']/Value}" valueKey="0"/>
            <Attr name="Size" value="{following::node()[Name='Size']/Value}" valueKey="0"/>
            <Attr name="Style" value="{following::node()[Name='Style']/Value}" valueKey="0"/>
        </complex>
    </xsl:template>
</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜