【问题标题】:XSLT iterating over child nodesXSLT 迭代子节点
【发布时间】:2013-02-22 15:28:19
【问题描述】:

这看起来很简单,但我似乎无法让它工作。

我的 xml 看起来像这样:

<bsar:BSAForm>
    <bsar:SubjectInformation>
        <bsar:LastNameOrNameOfEntity> Obama</bsar:LastNameOrNameOfEntity>
        <bsar:AddressBlock>
            <ucc:Address> 9 Dale Rd</ucc:Address>
            <ucc:City> Woodbury</ucc:City>
        </bsar:AddressBlock>
        <bsar:AddressBlock>
            <ucc:Address> 123 Fake St</ucc:Address>
            <ucc:City> Springfield</ucc:City>
        </bsar:AddressBlock>
    </bsar:SubjectInformation>
</bsar:BSAForm>

我需要遍历这两个元素并显示内容。我的 XSLT 如下所示:

<xsl:template match=/bsar:BSAForm">
     <xsl:apply-templates select="bsar:SubjectInformation"/>
</xsl:template>

<xsl:template match="bsar:SubjectInformation">
    <xsl:text xml:space="preserve">4A</xsl:text>
    <xsl:text xml:space="preserve">00001</xsl:text>
    <xsl:value-of select="bsar:LastNameOrNameOfEntity"/>
    <xsl:value-of select="'&#xD;&#xA;'"/> <!-- new line -->

    <xsl:apply-templates select="bsar:AddressBlock"/>
</xsl:template>

<xsl:template match="bsar:AddressBlock">

    <xsl:variable name="Addr" select="../bsar:AddressBlock"/>

    <xsl:text xml:space="preserve">4B</xsl:text>
    <xsl:text xml:space="preserve">00001</xsl:text>
    <xsl:value-of select="$Addr/ucc:Address"/>
    <xsl:value-of select="$Addr/ucc:City"/>
    <xsl:value-of select="'&#xD;&#xA;'"/> <!-- new line -->
</xsl:template>

输出应该如下:

4A 00001 Obama
4B 9 Dale Rd Woodbury
4B 123 Fake St Springfield

但是,输出是这样的:

4A 00001 Obama
4B 9 Dale Rd Woodbury
4B 9 Dale Rd Woodbury

我尝试了许多不同的方法来做到这一点,使用一个 for each,使用一个 for each 像这样:

 <xsl:variable name="header" select="."/>
 <xsl:for-each select="following-sibling::bsar:TelephoneBlock[ancestor::bsar:SubjectInformation[1] = $header]">

甚至从 for 循环中传入一个计数器并使用它来访问指定的元素,如下所示:

<xsl:for-each select="bsar:TelephoneBlock">
    <xsl:variable name="Index">
        <xsl:number count="bsar:TelephoneBlock" />
    </xsl:variable>

    <xsl:call-template name="SubjectPhone">
        <xsl:with-param name="$Index"/>
    </xsl:call-template>
</xsl:for-each>

<xsl:template name="SubjectPhone">
    <xsl:param name="Index"/>

    <xsl:variable name="Telephone" select="../bsar:TelephoneBlock[$Index]"/>
    ...
</xsl:template>

在所有这些情况下,它都会显示第一个地址两次。如果您发现我做错了什么,请告诉我。

提前致谢。

【问题讨论】:

    标签: xml xslt xslt-1.0


    【解决方案1】:
    <xsl:variable name="Addr" select="../bsar:AddressBlock"/>
    

    bsar:AddressBlock 模板内将Addr 变量设置为包含所有当前元素父级下的bsar:AddressBlock 元素的节点集,即当前的AddressBlock 及其所有兄弟AddressBlock 元素以及。当你以后来的时候

    <xsl:value-of select="$Addr/ucc:Address"/>
    

    这将选择一个包含$Addr中所有AddressBlock元素的所有ucc:Address子元素的节点集,然后将first这样的元素按文档顺序转换为其字符串值(定义XPath 1.0 中设置的节点的“字符串值”是其第一个节点的字符串值)。这将始终是第一个地址块中的ucc:Address,这就是为什么您会看到两次相同的地址。

    但是这个变量是不必要的,因为你在一个模板中,一次只适用于一个地址块 - 只是说

    <xsl:template match="bsar:AddressBlock">
        <xsl:text>4B</xsl:text>
        <xsl:text>00001</xsl:text>
        <xsl:value-of select="ucc:Address"/>
        <xsl:value-of select="ucc:City"/>
        <xsl:value-of select="'&#xD;&#xA;'"/> <!-- new line -->
    </xsl:template>
    

    select 表达式将与当前的 AddressBlock 相关,并将具体提取其 Address 和 City,并生成

    4A00001 Obama
    4B00001 9 Dale Rd Woodbury
    4B00001 123 Fake St Springfield
    

    这确实依赖于这样一个事实,即在原始 XML 中每个地址和城市值的开头都有一个前导空格,您可能更喜欢这样说

    <xsl:template match="bsar:AddressBlock">
        <xsl:text>4B </xsl:text>
        <xsl:text>00001 </xsl:text>
        <xsl:value-of select="normalize-space(ucc:Address)"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="normalize-space(ucc:City)"/>
        <xsl:value-of select="'&#xD;&#xA;'"/> <!-- new line -->
    </xsl:template>
    

    (注意xml:space="preserve"&lt;xsl:text&gt; 的默认值,因此您无需明确指定)

    【讨论】:

    • 没错。愿你活到一千年。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多