如何在for-each循环中使用不同的xpath进行XSLT转换

时间:2013-09-19 09:18:20

标签: xml xslt

这就是问题:转换后的XSLT应该显示两个电话号码,< Phone_1>和< Phone_2>,每个一个。仅添加传真标签以供参考。

这是我必须转换的XML片段:

    <DirPartyContactInfoView>
        <Locator>08-922100</Locator>
        <Type>Phone</Type>
    </DirPartyContactInfoView>
        <Locator>073-6564865</Locator>
        <Type>Phone</Type>
    </DirPartyContactInfoView>    
        <Locator>08-922150</Locator>
        <Type>Fax</Type>
    </DirPartyContactInfoView>

这是我目前对此片段的XSLT的看法。到目前为止,我已经尝试将变量设置为条件,知道它只能设置变量值一次而不能修改它。

<xsl:for-each select="DirPartyContactInfoView">
    <xsl:choose>
        <xsl:when test="Type='Phone'">
            <xsl:variable name="Phone1" />
            <xsl:choose>                                        
                <xsl:when test="Phone1=''">     
                    <xsl:variable name="Phone1" select="Locator" />                                 
                    <Phone_1>
                        <xsl:value-of select="Locator" />
                    </Phone_1>
                </xsl:when>
                <xsl:otherwise>
                    <Phone_2>
                        <xsl:value-of select="Locator" />
                    </Phone_2>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:when test="Type='Fax'">
            <Fax>
                <xsl:value-of select="Locator" />
            </Fax>
        </xsl:when>
    </xsl:choose>
</xsl:for-each>

然而我得到两个&lt; Phone_2&gt;关于输出,我完全没有想法。我猜我不能使用这样的变量。有什么方法可以解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

对于(看似)简单的要求,这非常复杂。如果我理解你的话,试试这个:

<xsl:template match="/">
    <xsl:apply-templates select='root/DirPartyContactInfoView[Type="Phone"]' />
</xsl:template>
<xsl:template match='DirPartyContactInfoView'>
    <xsl:element name='phone_{position()}'>
        <xsl:value-of select='Locator' />
    </xsl:element>
</xsl:template>

我假设了一个根节点root,因为您的XML没有向我们展示您拥有的根节点。

Demo (请参阅输出来源)。

XSLT中一个好的经验法则是,如果您发现自己严重依赖for-each构造或变量,那么可能有更好的方法。

答案 1 :(得分:1)

你真的需要一个xsl:for-each循环吗?您也可以直接使用XPath访问<Locator>元素:

 //DirPartyContactInfoView[1]/Locator
 //DirPartyContactInfoView[2]/Locator

如果你仍然需要xsl:for-each循环,也许这样的东西有帮助:

<xsl:for-each select="DirPartyContactInfoView">
    <xsl:choose>
        <xsl:when test="Type='Phone'">
            <xsl:choose>                                        
                <xsl:when test="position()='1'">     
                    <Phone_1>
                        <xsl:value-of select="Locator" />
                    </Phone_1>
                </xsl:when>
                <xsl:otherwise>
                    <Phone_2>
                        <xsl:value-of select="Locator" />
                    </Phone_2>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
    </xsl:choose>
</xsl:for-each>

答案 2 :(得分:0)

@flaskis通过更改问题回复了之前的答案,所以我有点不愿意权衡,但这可能是一个合适的解决方案的形式

<xsl:template match="phone[1]">...</xsl:template>
<xsl:template match="phone[2]">...</xsl:template>

其中不同的模板规则应用于第一个和第二个电话元素。