如何在XSLT的单个for-each中选择多个节点

9

我希望学习XSLT,但我更喜欢通过实例来学习。 我想执行一个简单的模式到模式转换。 如何在一次转换中执行此转换(我的当前解决方案使用了两个步骤,并且丢失了客户的原始顺序)?

来源:

<?xml version="1.0" encoding="UTF-8"?>
<sampleroot>

<badcustomer>
    <name>Donald</name>
    <address>Hong Kong</address>
    <age>72</age>
</badcustomer>

<goodcustomer>
    <name>Jim</name>
    <address>Wales</address>
    <age>22</age>
</goodcustomer>

<goodcustomer>
    <name>Albert</name>
    <address>France</address>
    <age>51</age>
</goodcustomer>

</sampleroot>

收件人:

<?xml version="1.0" encoding="UTF-8"?>
<records>

<record id="customer">
    <name>Donald</name>
    <address>Hong Kong</address>
    <age>72</age>
    <customertype>bad</customertype>
</record>

<record id="customer">
    <name>Jim</name>
    <address>Wales</address>
    <age>22</age>
    <customertype>good</customertype>
</record>

<record id="customer">
    <name>Albert</name>
    <address>France</address>
    <age>51</age>
    <customertype>good</customertype>
</record>

</records>

我已经用一种不好的方法解决了这个问题(我失去了客户的顺序,我认为我必须多次解析文件):

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/sampleroot">

    <records>

        <xsl:for-each select="goodcustomer">
            <record id="customer">
                <name><xsl:value-of select="name" /></name>
                <address><xsl:value-of select="address" /></address>
                <age><xsl:value-of select="age" /></age>
                <customertype>good</customertype>
            </record>
        </xsl:for-each>

        <xsl:for-each select="badcustomer">
            <record id="customer">
                <name><xsl:value-of select="name" /></name>
                <address><xsl:value-of select="address" /></address>
                <age><xsl:value-of select="age" /></age>
                <customertype>bad</customertype>
            </record>
        </xsl:for-each>

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

请问是否有人能帮我用正确的XSLT结构,只需使用一次解析(仅一个for-each)?谢谢,Chris。

1
很好的问题,Chris (+1)。请看我的答案,有一个很好的解决方案。 :) - Dimitre Novatchev
1个回答

11

尽可能避免使用 <xsl:for-each> 是一个良好的XSLT实践。

以下是一个简单的解决方案,使用了这个原则:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
  <records>
    <xsl:apply-templates/>
  </records>
 </xsl:template>

 <xsl:template match="badcustomer | goodcustomer">
  <record>
   <xsl:apply-templates/>
   <customertype>
     <xsl:value-of select="substring-before(name(), 'customer')"/>
   </customertype>
  </record>
 </xsl:template>
</xsl:stylesheet>

请注意

  1. 仅使用模板和 <xsl:apply-templates>

  2. 使用identity规则及其必要的覆盖。这是最基本的XSLT设计模式之一。


谢谢,我可以问最后一个问题吗?如果我想从原始的XML模式中传递属性,我该如何调整XSLT以使其工作?<badcustomer> <name myattribute="attributevalue" >Donald</name> <address myattribute2="attributevalue2" >香港</address> <age>72</age> </badcustomer> - Chris
@Chris:请以正确格式的代码/XML作为一个新问题来提问。同时,您使用了“schema”这个词不当。实际上,您所指的是“源XML文档”,或者是该文档类型的架构实例。 - Dimitre Novatchev
感谢您提供的信息并纠正我错误使用“模式”的问题。我已经解决了后续问题,所以现在不需要提出新问题了。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接