我有一个由2个不同的xml文件组成的1个大型xml文件。 我想要做的是,当我创建一个CSV文件时,我希望能够从文件的第二部分中获取与第一部分匹配的数据。 我使用a 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="'
'" />
<xsl:variable name="tab" select="'	'" />
<xsl:variable name="comma" select="','" />
<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
节点的值。
如何让它显示值?
如果需要更多信息,我可以添加内容。
答案 0 :(得分:1)
我无法添加评论来要求澄清您期望输出的内容,但有些意见:
目前,您的样式表将遍历每个company_id元素,对于每个找到它,它将遍历每个Company_Data / Report_Entry元素。 您看到N / A,因为对于每个company_id,它会检查每个Company_Data / Report_Entry,并为任何与当前company_id不匹配的任何内容输出N / A. 对我来说,看起来你只需要删除其他(在这种情况下你不需要选择,只需一个if)。 请注意,当我尝试运行样式表时,我得到的是001,Test1,N / A,Test1,N / A,与您的稍有不同(但我必须为每个结束标记添加一个缺失的内容)。
就代码和名称元素而言,因为您处于for循环中,焦点已转移到循环播放的元素(Report_Data / Company_Data / Report_Entry),因此您可以使用将从该循环元素导航的相对路径。 所以你可以使用“代码”或“名称”。你甚至不需要“./”,因为这会产生相同的结果。
答案 1 :(得分:1)
您无需在此处使用内部 xsl:for-each 循环来查找公司名称。你可以在这里使用 xsl:variable 和一个select参数来放置你的'contains'表达式
<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
,那么这是一个“绝对”表达式,它从顶级文档节点开始,并始终返回第一个 company_id XML。
但无论如何,你可以简单地输出这个变量,或者使用 xsl:choose 来输出'NA'而不是变量是空的(即没有找到公司名称)。
如果不是因为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))" />