简体   繁体   English

使用XSLT 1.0对输出进行分组

[英]Grouping output using XSLT 1.0

I've been given the follow XML (produced by someone from an Excel spreadsheet) 我得到了以下XML(由Excel电子表格中的某人生成)

<Records>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section A</Section>
    <label>Option X 1</label>
    <Keyword>Unique KW 1</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section B</Section>
    <label>Option X 2</label>
    <Keyword>Unique KW 2</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 2</Domain>
    <Section>Section A</Section>
    <label>Option X 3</label>
    <Keyword>Unique KW 3</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section A</Section>
    <label>Option X 4</label>
    <Keyword>Unique KW 4</Keyword>
    <Control>Checkbox</Control>
    <Default>FALSE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section B</Section>
    <label>Option X 5</label>
    <Keyword>Unique KW 5</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 2</Domain>
    <Section>Section B</Section>
    <label>Option X 6</label>
    <Keyword>Unique KW 6</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
<record>
    <Domain>Domain 1</Domain>
    <Section>Section A</Section>
    <label>Option X 7</label>
    <Keyword>Unique KW 7</Keyword>
    <Control>Checkbox</Control>
    <Default>TRUE</Default>
</record>
</Records>

And I've been asked to transform it into the following using XSLT 1.0 我被要求使用XSLT 1.0将其转换为以下内容

<Configuration>
<Domain name="Domain 1">
    <Section name="Section A">
        <Option keyword="Unique KW 1" name="Option X 1">
            <Control type="Checkbox" default="True" />
        </Option>
        <Option keyword="Unique KW 3" name="Option X 3">
            <Control type="Checkbox" default="True" />
        </Option>
        <Option keyword="Unique KW 7" name="Option X 7">
            <Control type="Checkbox" default="True" />
        </Option>
    </Section>
    <Section name="Section B">
        <Option keyword="Unique KW 2" name="Option X 2">
            <Control type="Checkbox" default="True" />
        </Option>
        <Option keyword="Unique KW 5" name="Option X 5">
            <Control type="Checkbox" default="True" />
        </Option>
    </Section>
</Domain>
<Domain name="Domain 2">
    <Section name="Section A">
        <Option keyword="Unique KW 3" name="Option X 3">
            <Control type="Checkbox" default="True" />
        </Option>       
    </Section>
    <Section name="Section B">
        <Option keyword="Unique KW 6" name="Option X 6">
            <Control type="Checkbox" default="True" />
        </Option>       
    </Section>
</Domain>
</Configuration>

I've used XSLT in a limited capacity in the past but I'm struggling getting a single element out (eg Domain and Section), the output I get is one per element in the source where I need 1 per value in the source (if that makes sense). 过去,我曾以有限的容量使用XSLT,但我一直在努力获取单个元素(例如Domain和Section),我得到的输出是源中每个元素一个,而我需要源中每个值一个(如果有道理)。 I just seem to get lots of 我似乎得到很多

Domain instead of just two (Domain 1 and Domain 2), same with the Section 域而不是两个(域1和域2),与Section相同

Is there any way of doing this with XSLT 1.0 or am I just wasting my time? 使用XSLT 1.0可以做到这一点吗?还是我只是在浪费时间?

(Also, the data I've given is an example, edited to remove sensitive data and size, there are far more Domains and Section etc) (此外,我提供的数据是一个示例,经过编辑以删除敏感数据和大小,还有更多的Domains和Section等)

(The little I've got so far) (到目前为止我所获得的很少)

<xsl:stylesheet version="1.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:ms="urn:schemas-microsoft-com:xslt"
            xmlns:dt="urn:schemas-microsoft-com:datatypes">
<xsl:output media-type="xml" indent="yes" />

<xsl:template match="/Records">
<Configuration>
  <xsl:for-each select="record/Domain">
    <Domain name="{text()}">
    <Section name="{../Section/text()}">
      <Option keyword="{../Keyword/text()}">
        <Control type="{../Control/text()}"/>
      </Option>
    </Section>
    </Domain>
  </xsl:for-each>
</Configuration>
</xsl:template>
</xsl:stylesheet>

EDIT: After looking at Michaels link (thanks) I'm getting closer. 编辑:看了迈克尔斯的链接后(谢谢),我越来越近了。 The outer group (Domain) is working but the inner group isn't 外部组(域)正在工作,但是内部组没有

  <xsl:key name="domain-name" match="record" use="Domain" />
  <xsl:key name="section-name" match="record" use="Section" />

  <xsl:template match="/Records">
    <Configuration>
      <xsl:for-each select="record[count(. | key('domain-name', Domain)[1]) = 1]">
        <xsl:sort select="Domain" />
        <Domain name="{Domain}">
          <xsl:for-each select="record[count(. | key('section-name', Section)[1]) = 1]">
            <xsl:sort select="Section" />
              <Section name="{Section}">
                <Option keyword="{Keyword/text()}">
                  <Control type="{Control/text()}"/>
                </Option>
              </Section>
            </xsl:for-each>
          </Domain>
        </xsl:for-each>
      </Configuration>
    </xsl:template>

Is giving me 给我

  <Configuration>
    <Domain name="Domain 1" />
    <Domain name="Domain 2" />
  </Configuration>

For your inner grouping, you are grouping Section elements within Domain , so both elements need to be within the key 对于内部分组,您是将Domain元素中的Section元素分组,因此两个元素都必须在键中

<xsl:key name="section-name" match="record" use="concat(Domain, '|', Section)" />

The inner xsl:for-each then needs to be changed to use they new key format. 然后需要更改内部的xsl:for-each以使用新的密钥格式。 But also because you are doing xsl:for-each select="group...." which won't work because you are currently positioned on a record and so the inner xsl:for-each is looking for a child element also called record . 而且还因为您正在执行xsl:for-each select="group...." ,该操作将不起作用,因为您当前位于record ,因此内部xsl:for-each正在寻找一个子元素,该元素也称为record It should look like this, which only consider record elements for the current Domain value 它看起来应该像这样,它只考虑当前Domain值的record元素

<xsl:for-each select="key('domain-name', Domain)[count(. | key('section-name', concat(Domain, '|', Section))[1]) = 1]">

Try this XSLT 试试这个XSLT

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

  <xsl:key name="domain-name" match="record" use="Domain" />
  <xsl:key name="section-name" match="record" use="concat(Domain, '|', Section)" />

  <xsl:template match="/Records">
    <Configuration>
      <xsl:for-each select="record[count(. | key('domain-name', Domain)[1]) = 1]">
        <xsl:sort select="Domain" />
        <Domain name="{Domain}">
          <xsl:for-each select="key('domain-name', Domain)[count(. | key('section-name', concat(Domain, '|', Section))[1]) = 1]">
            <xsl:sort select="Section" />
              <Section name="{Section}">
                <Option keyword="{Keyword/text()}">
                  <Control type="{Control/text()}"/>
                </Option>
              </Section>
            </xsl:for-each>
          </Domain>
        </xsl:for-each>
      </Configuration>
    </xsl:template>
</xsl:stylesheet>

It looks like you also then need a third level of grouping, on Keyword , but you should be able to work that out now (you will need the key to consider Domain , Section and Keyword ) 看来您还需要在Keyword上进行第三级分组,但是您现在应该可以解决这个问题(您需要使用Key来考虑DomainSectionKeyword

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM