使用XSLT根据子字符串对数据进行分组。

huangapple go评论58阅读模式
英文:

Using XSLT to Group Data Based on Substrings

问题

我正在尝试使用XSLT将XML文档中的数据分组为两个类别。具体来说,给定一个包含三个项目的列表,我希望XSLT将这三个项目导出为两个不同的组(食物和建筑)。我尝试通过子字符串来对数据进行分组。

XML:

<?xml version="1.0" encoding="UTF-8"?>
<items> 
    <Skyscraper>Willis Tower</Skyscraper> 
    <Small_fruit>blueberry</Small_fruit> 
    <Big_fruit>watermelon </Big_fruit> 
</items>

我尝试过的XSLT:

<?xml version="1.1" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output method="xml"/>  
    <xsl:template match = "/">      
        <items>
            <xsl:element name = "Fruit">
                <xsl:for-each-group select="//items" group-by="*[contains(local-name(), 'fruit')]">
                    <xsl:copy-of select="."/>
                    <xsl:value-of select="current-grouping-key()"/>
                    <xsl:if test="not(position() = last())">,</xsl:if>
                </xsl:for-each-group>
            </xsl:element>
        </items>
    </xsl:template> 
</xsl:stylesheet>

我期望的XML输出:

<?xml version="1.0" encoding="UTF-8"?>
<items> 
    <Building>
        <Skyscraper>Willis Tower</Skyscraper>
    </Building> 
    <Food>
        <Small_fruit>blueberry</Small_fruit> 
        <Big_fruit>watermelon </Big_fruit> 
    </Food>
</items>

编辑后的XSLT:

<?xml version="1.1" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <!-- airport XSLT -->
    <xsl:output method="xml"/>  
    <xsl:template match = "/">      
        <items>
            <xsl:element name = "fruit">
                <xsl:for-each-group select="/items/*" group-by="*[contains(local-name(), 'fruit')]">
                    <xsl:copy-of select="."/>
                    <xsl:value-of select="current-grouping-key()"/>
                    <xsl:if test="not(position() = last())">&#xa;</xsl:if>
                </xsl:for-each-group>
            </xsl:element>
            <xsl:element name = "building">
                <xsl:for-each-group select="/items/*" group-by="*[contains(local-name(), 'sky')]">
                    <xsl:copy-of select="."/>
                    <xsl:value-of select="current-grouping-key()"/>
                    <xsl:if test="not(position() = last())">&#xa;</xsl:if>
                </xsl:for-each-group>
            </xsl:element>
        </items>
    </xsl:template> 
</xsl:stylesheet>
英文:

I am trying to use XSLT to group data from an XML document into two categories. Specifically, given a list of three items, I want the XSLT to export the three items as two different groups (food & buildings). I'm attempting to do this by grouping the data by substrings.

XML:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;items&gt; 
    &lt;Skyscraper&gt;Willis Tower&lt;/Skyscraper&gt; 
    &lt;Small_fruit&gt;blueberry&lt;/Small_fruit&gt; 
    &lt;Big_fruit&gt;watermelon &lt;/Big_fruit&gt; 
&lt;/items&gt;

What I tried (XSLT):

&lt;?xml version=&quot;1.1&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
    xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot; exclude-result-prefixes=&quot;xs&quot; version=&quot;2.0&quot;&gt;
    &lt;xsl:output method=&quot;xml&quot;/&gt;  
    &lt;xsl:template match = &quot;/&quot;&gt;      
        &lt;items&gt;
            &lt;xsl:element name = &quot;Fruit&quot;&gt;
                &lt;xsl:for-each-group select=&quot;//items&quot; group-by=&quot;*[contains(local-name(), &#39;fruit&#39;)]&quot;&gt;
                    &lt;xsl:copy-of select = &quot;.&quot;/&gt;
                    &lt;xsl:value-of select=&quot;current-grouping-key()&quot;/&gt;
                    &lt;xsl:if test = &quot;not(position() = last())&quot;&gt;,&lt;/xsl:if&gt;
                &lt;/xsl:for-each-group&gt;
            &lt;/xsl:element&gt;
        &lt;/items&gt;
    &lt;/xsl:template&gt; 
&lt;/xsl:stylesheet&gt;

What I expected (XML):

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;items&gt; 
    &lt;Building&gt;
        &lt;Skyscraper&gt;Willis Tower&lt;/Skyscraper&gt;
    &lt;/Building&gt; 
    &lt;Food&gt;
        &lt;Small_fruit&gt;blueberry&lt;/Small_fruit&gt; 
        &lt;Big_fruit&gt;watermelon &lt;/Big_fruit&gt; 
    &lt;/Food&gt;
&lt;/items&gt;

Edited XSLT

&lt;?xml version=&quot;1.1&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
    xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot; exclude-result-prefixes=&quot;xs&quot; version=&quot;2.0&quot;&gt;
    &lt;!-- airport XSLT --&gt;
    &lt;xsl:output method=&quot;xml&quot;/&gt;  
    &lt;xsl:template match = &quot;/&quot;&gt;      
        &lt;items&gt;
            &lt;xsl:element name = &quot;fruit&quot;&gt;
                &lt;xsl:for-each-group select=&quot;/items/*&quot; group-by=&quot;*[contains(local-name(), &#39;fruit&#39;)]&quot;&gt;
                    &lt;xsl:copy-of select = &quot;.&quot;/&gt;
                    &lt;xsl:value-of select=&quot;current-grouping-key()&quot;/&gt;
                    &lt;xsl:if test = &quot;not(position() = last())&quot;&gt;&amp;#xa;&lt;/xsl:if&gt;
                &lt;/xsl:for-each-group&gt;
            &lt;/xsl:element&gt;
            &lt;xsl:element name = &quot;building&quot;&gt;
                &lt;xsl:for-each-group select=&quot;/items/*&quot; group-by=&quot;*[contains(local-name(), &#39;sky&#39;)]&quot;&gt;
                    &lt;xsl:copy-of select = &quot;.&quot;/&gt;
                    &lt;xsl:value-of select=&quot;current-grouping-key()&quot;/&gt;
                    &lt;xsl:if test = &quot;not(position() = last())&quot;&gt;&amp;#xa;&lt;/xsl:if&gt;
                &lt;/xsl:for-each-group&gt;
            &lt;/xsl:element&gt;
        &lt;/items&gt;
    &lt;/xsl:template&gt; 
&lt;/xsl:stylesheet&gt;

答案1

得分: 1

尝试这种方式?

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="/items">      
        <items>
            <xsl:for-each-group select="*" group-by="contains(local-name(), 'fruit')">
                <xsl:element name="{if(current-grouping-key()) then 'Food' else 'Building'}">
                    <xsl:copy-of select="current-group()"/>
                </xsl:element>
            </xsl:for-each-group>
        </items>
    </xsl:template>
    
</xsl:stylesheet>

P.S. 你也可以简单地这样做:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="/items">   
        <xsl:variable name="fruit" select="*[contains(local-name(), 'fruit')]" />   
        <items>
            <Building>
                <xsl:copy-of select="* except $fruit"/>
            </Building>
            <Food>
                <xsl:copy-of select="$fruit"/>
            </Food>
        </items>
    </xsl:template>
    
</xsl:stylesheet>

区别在于即使一个(或两者)为空,这种方式始终会创建两个组。

英文:

Try it this way?

XSLT 2.0

&lt;xsl:stylesheet version=&quot;2.0&quot; 
xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
&lt;xsl:output method=&quot;xml&quot; version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; indent=&quot;yes&quot;/&gt;

&lt;xsl:template match=&quot;/items&quot;&gt;      
    &lt;items&gt;
        &lt;xsl:for-each-group select=&quot;*&quot; group-by=&quot;contains(local-name(), &#39;fruit&#39;)&quot;&gt;
            &lt;xsl:element name=&quot;{if(current-grouping-key()) then &#39;Food&#39; else &#39;Building&#39;}&quot;&gt;
                &lt;xsl:copy-of select=&quot;current-group()&quot;/&gt;
            &lt;/xsl:element&gt;
        &lt;/xsl:for-each-group&gt;
    &lt;/items&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

P.S. You could also do simply:

&lt;xsl:stylesheet version=&quot;2.0&quot; 
xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
&lt;xsl:output method=&quot;xml&quot; version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; indent=&quot;yes&quot;/&gt;

&lt;xsl:template match=&quot;/items&quot;&gt;   
	&lt;xsl:variable name=&quot;fruit&quot; select=&quot;*[contains(local-name(), &#39;fruit&#39;)]&quot; /&gt;   
    &lt;items&gt;
		&lt;Building&gt;
			&lt;xsl:copy-of select=&quot;* except $fruit&quot;/&gt;
		&lt;/Building&gt;
		&lt;Food&gt;
			&lt;xsl:copy-of select=&quot;$fruit&quot;/&gt;
		&lt;/Food&gt;
	&lt;/items&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

The difference is this will always create both groups, even if one (or both) of them is empty.

huangapple
  • 本文由 发表于 2023年6月2日 05:50:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76385942.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定