英文:
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())">
</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())">
</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:
<?xml version="1.0" encoding="UTF-8"?>
<items> 
    <Skyscraper>Willis Tower</Skyscraper> 
    <Small_fruit>blueberry</Small_fruit> 
    <Big_fruit>watermelon </Big_fruit> 
</items>
What I tried (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>
What I expected (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>
Edited 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>
答案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
<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. You could also do simply:
<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>
The difference is this will always create both groups, even if one (or both) of them is empty.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论