【问题标题】:Call Template with Parameter and Output Value - XSLT带有参数和输出值的调用模板 - XSLT
【发布时间】:2013-12-11 18:48:08
【问题描述】:

我有一个由 2 个不同的 xml 文件组成的 1 个大 xml 文件。 我想要做的是,当我创建一个 CSV 文件时,我希望能够从文件的第二部分中获取与第一部分匹配的数据。 我使用 for each 循环遍历文件第一部分中的所有数据,然后使用嵌套循环来获取匹配的数据。 这是 XML 布局:

<?xml version="1.0" encoding="UTF-8"?>
<Report_Data>
    <Report_Entry>
        <company_id>001</company_id>
        <dept>TestDept</dept>
    </Report_Entry>
    <Report_Entry>
    </Report_Entry>
    <Company_Data>
        <Report_Entry>
            <code>1</code>
            <name>Test1</name>
        </Report_Entry>
        <Report_Entry>
            <code>2</code>
            <name>Test2</name>
        </Report_Entry>
    </Company_Data>
</Report_Data>

我希望在我的 CSV 中将来自 Company_Data 节点的名称插入到输出中,紧跟在 company_id 之后。

这是我的 XSL 文件(它目前不起作用,它循环并为输出文件中的每个公司数据节点输出 N/A):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wd="urn:com.workday/bsvc">
<xsl:output method="text" encoding="utf-8" media-type="text/plain" />
<xsl:strip-space  elements="*"/>

<xsl:variable name="newline" select="'&#x0A;'" />
<xsl:variable name="tab" select="'&#x09;'" />
<xsl:variable name="comma" select="'&#x2C;'" />
<xsl:variable name="padding" select="'                              '" />

<xsl:variable name="ID" select="concat('COMPANY ID', $padding)" />
<xsl:variable name="NAME" select="concat('COMPANY NAME', $padding)" />
<xsl:variable name="DEPT" select="concat('DEPARTMENT', $padding)" />

<xsl:template match="/">
    <xsl:value-of select="$ID"/><xsl:value-of select="$comma"/>
    <xsl:value-of select="$NAME"/><xsl:value-of select="$comma"/>
    <xsl:value-of select="$DEPT"/><xsl:value-of select="$comma"/>

    <xsl:for-each select="/Report_Data/Report_Entry">
    <xsl:value-of select="translate(substring(concat(company_id, $padding), 1, string-length($ID)), ',', ' ')" /><xsl:value-of select="$comma"/>

    <xsl:call-template name="company_name">
        <xsl:with-param name="id_number" select="company_id"></xsl:with-param>
</xsl:call-template>

    <xsl:value-of select="translate(substring(concat(dept, $padding), 1, string-length($DEPT)), ',', ' ')" /><xsl:value-of select="$comma"/>
</xsl:for-each>

</xsl:template>

<xsl:template name="company_name" match="/wd:Report_Data/wd:Company_Data">
<xsl:param name="id_number"></xsl:param>
<xsl:for-each select="/wd:Report_Entry">
    <xsl:if test="contains($id_number, code)">
        <xsl:value-of select="/name/text()"/>
    </xsl:if>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

我的输出如下所示:

1, TestDept

代替:

1, Test1, TestDept

它没有输出name 节点的值。 如何让它显示值?

如果需要更多信息,我可以添加内容。

【问题讨论】:

    标签: xml xslt csv


    【解决方案1】:

    您无需在此处使用内部 xsl:for-each 循环来查找公司名称。您可以在此处使用带有选择参数的 xsl:variable,您可以在其中放置“包含”表达式

    <xsl:for-each select="Report_Data/Report_Entry">
        <xsl:variable 
             name="company_name" 
             select="/Report_Data/Company_Data/Report_Entry[contains(current()/company_id, code)]/name" />
    

    注意这里使用current(),这是为了确保表达式使用你当前的Report_Data/Report_Entry元素的company_id与您在表达式中搜索的 Company_Data/Report_Entry 不同。如果您要执行当前正在执行的操作,即/Report_Data/Report_Entry/company_id,那么这是一个“绝对”表达式,它从顶级文档节点开始,并将始终返回 XML 中的第一个 company_id .

    但无论如何,您可以简单地输出此变量,或者使用 xsl:choose 来输出“NA”,而不是在变量为空时(即未找到公司名称)。 p>

    如果不是因为 id 不匹配,这种查找值通常使用键更好地处理。要通过代码查找 Report_Entry,您可以定义一个键,如下所示

    <xsl:key name="company" match="Company_Data/Report_Entry" use="code" />
    

    然后查找它,你可以做这样的事情......

    <xsl:for-each select="Report_Data/Report_Entry">
        <xsl:variable name="company_name" select="key('company', company_id)" />
    

    当然,这在您的情况下会失败,因为 id 并不完全相同,但也许您可以删除前导零。试试这个吧。

    <xsl:for-each select="Report_Data/Report_Entry">
        <xsl:variable name="company_name" select="key('company', number(company_id))" />
    

    【讨论】:

      【解决方案2】:

      我无法添加评论以要求澄清您期望输出的确切内容,但有一些观察:

      目前,您的样式表将遍历每个 company_id 元素,并且对于找到的每个元素,它将遍历每个 Company_Data/Report_Entry 元素。 您看到的是 N/A,因为对于每个 company_id,它会检查每个 Company_Data/Report_Entry,并为与当前 company_id 不匹配的任何内容输出 N/A。 对我来说,看起来你只需要删除 else (在这种情况下你不需要选择,只需要一个 if)。 请注意,当我尝试运行您的样式表时,我得到了 001,Test1,N/A,,Test1,N/A,与您的略有不同(但我必须添加一个缺少的 for-each 结束标记)。

      就代码和名称元素而言,由于您处于 for 循环中,因此焦点已转移到正在循环的元素 (Report_Data/Company_Data/Report_Entry),因此您可以使用将从该循环元素导航的相对路径。 所以你可以只使用“代码”或“名称”。您甚至不需要“./”,因为这会产生相同的结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-23
        • 1970-01-01
        • 1970-01-01
        • 2012-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多