XSLT分组与多个组集合

时间:2011-04-20 21:15:20

标签: xslt grouping

我需要一些关于这个XSLT的帮助。它正在按照它的方式工作,但是我已经改变了要求... :-)而且我需要修改它以给我预期的输出。 我正在寻找一些指导和帮助。

说明: 我有像这样的源码xml

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

在上面的xml中,我需要查看节点“Type”并按类型对它们进行分组。例如,如果我有5个属性,其中Type是常见的,4个属性,其中Type是category,3个属性,其中Type是Complex,那么将它们分组为这样。

<?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>

从上面可以看出,我是第一组共同的&amp;类别并为常见的Complex创建一个组集合。这工作正常(虽然我正在使用Iteration ......: - ))

问题是我只为1个属性创建了一个Complex,其中Name = Collection并且它是硬编码的。但是,新要求是我为另一个属性创建了一个复杂的集合,其中name = Cost。

这是我遇到问题的地方。我怎样才能做到这一点。下面是示例源和输出xml和XSLT。在此先感谢。

源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>

预期输出 我需要2个收集节点,我需要输入当前日期。 注意在Collection Node中我可以有多个Complex节点。但是,在Cost中,我只有1个Complex节点。

<?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 :根据Michael的评论更新

<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">
          <xsl:value-of select="$count"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>

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

1 个答案:

答案 0 :(得分:0)

虽然远非完美,但这里有一个样式表可以产生你想要的输出。我不确定修复每个复杂的属性或修复集合的程度。如果这有帮助,请告诉我。

<?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>