Return 仅从 for-each 中首次找到值
Return only first found value from for-each
我需要找到等于 xbrl:concept": "se:Bank"
的“value/pair”。 XSLT 找到 2 个“value/pairs”。由于数据提取是针对单个 header,因此我只需要 1 heading
个答案。在下面的代码中,我试图通过使用 [position() = 1]
来限制 xsl:for-each
但仍然获得 2 个索引位置的 return。
这个例子被最小化以适合一个正确的问题。在真实场景中,我生成了大约 100-130 个标题。
这可以用 for-each
解决吗?还是我应该移动到另一个 XSLT 元素?
代码在xsltfiddle
下面是相同的代码:
JSON
<data>
{
"report": {
"facts": [
{
"xbrl:concept": "se:Bank",
"numericValue": 1000,
"heading": "Bank balance"
},
{
"xbrl:concept": "se:CompanyName",
"value": "Great Company Ltd"
},
{
"xbrl:concept": "se:Bank",
"numericValue": 3000,
"heading": "Bank balance"
}
]
}
}
</data>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:output method="xhtml" indent="yes" html-version="5"/>
<xsl:mode on-no-match="shallow-skip"/>
<!-- Parse JSON to XML -->
<xsl:template match="data">
<xsl:apply-templates select="json-to-xml(.)/*"/>
</xsl:template>
<!-- Printout heading -->
<xsl:template match="//*[@key='facts']">
<xsl:for-each select="//*[@key='xbrl:concept'][. = 'se:Bank'][position() = 1]">
<xsl:value-of select="../*[@key='heading']"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
结果
Bank balanceBank balance
想要的结果
Bank balance
我将节点集合放入一个变量中,然后 select 第一个
<xsl:template match="//*[@key='facts']">
<xsl:variable name="headings" select="//*[@key='xbrl:concept'][. = 'se:Bank']/../*[@key='heading']"/>
<xsl:value-of select="$headings[1]"/>
</xsl:template>
或者更简单,将这些节点传递给 head
<xsl:template match="//*[@key='facts']">
<xsl:value-of select="head(//*[@key='xbrl:concept'][. = 'se:Bank']/../*[@key='heading'])"/>
</xsl:template>
不要使用 for-each
,只需 select 序列的第一个元素,例如head
函数:
<xsl:template match="//*[@key='facts']">
<xsl:value-of select="head(fn:map[fn:string[@key = 'xbrl:concept'][. = 'se:Bank']]/fn:string[@key = 'heading'])"/>
声明xmlns:fn="http://www.w3.org/2005/xpath-functions"
,我认为根据key
属性完全忽略元素名称并简单地select是没有意义的
构造 //*[1]
经常会导致问题:它解析为 /descendant-or-self::node()/child::*[1]
,它选择每个作为其父项的第一个子项的后代。这里人们通常想要的是(//*)[1]
,它选择整个文档中的第一个后代。
问题在这里被掩盖了,因为它以复杂表达式的形式出现//*[@key='xbrl:concept'][. = 'se:Bank'][position() = 1]
,但问题是一样的;你想要的是 (//*[@key='xbrl:concept'][. = 'se:Bank'])[position() = 1]
,或者更简洁地说 (//*[@key='xbrl:concept'][. = 'se:Bank'])[1]
.
我需要找到等于 xbrl:concept": "se:Bank"
的“value/pair”。 XSLT 找到 2 个“value/pairs”。由于数据提取是针对单个 header,因此我只需要 1 heading
个答案。在下面的代码中,我试图通过使用 [position() = 1]
来限制 xsl:for-each
但仍然获得 2 个索引位置的 return。
这个例子被最小化以适合一个正确的问题。在真实场景中,我生成了大约 100-130 个标题。
这可以用 for-each
解决吗?还是我应该移动到另一个 XSLT 元素?
代码在xsltfiddle
下面是相同的代码:
JSON
<data>
{
"report": {
"facts": [
{
"xbrl:concept": "se:Bank",
"numericValue": 1000,
"heading": "Bank balance"
},
{
"xbrl:concept": "se:CompanyName",
"value": "Great Company Ltd"
},
{
"xbrl:concept": "se:Bank",
"numericValue": 3000,
"heading": "Bank balance"
}
]
}
}
</data>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:output method="xhtml" indent="yes" html-version="5"/>
<xsl:mode on-no-match="shallow-skip"/>
<!-- Parse JSON to XML -->
<xsl:template match="data">
<xsl:apply-templates select="json-to-xml(.)/*"/>
</xsl:template>
<!-- Printout heading -->
<xsl:template match="//*[@key='facts']">
<xsl:for-each select="//*[@key='xbrl:concept'][. = 'se:Bank'][position() = 1]">
<xsl:value-of select="../*[@key='heading']"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
结果
Bank balanceBank balance
想要的结果
Bank balance
我将节点集合放入一个变量中,然后 select 第一个
<xsl:template match="//*[@key='facts']">
<xsl:variable name="headings" select="//*[@key='xbrl:concept'][. = 'se:Bank']/../*[@key='heading']"/>
<xsl:value-of select="$headings[1]"/>
</xsl:template>
或者更简单,将这些节点传递给 head
<xsl:template match="//*[@key='facts']">
<xsl:value-of select="head(//*[@key='xbrl:concept'][. = 'se:Bank']/../*[@key='heading'])"/>
</xsl:template>
不要使用 for-each
,只需 select 序列的第一个元素,例如head
函数:
<xsl:template match="//*[@key='facts']">
<xsl:value-of select="head(fn:map[fn:string[@key = 'xbrl:concept'][. = 'se:Bank']]/fn:string[@key = 'heading'])"/>
声明xmlns:fn="http://www.w3.org/2005/xpath-functions"
,我认为根据key
属性完全忽略元素名称并简单地select是没有意义的
构造 //*[1]
经常会导致问题:它解析为 /descendant-or-self::node()/child::*[1]
,它选择每个作为其父项的第一个子项的后代。这里人们通常想要的是(//*)[1]
,它选择整个文档中的第一个后代。
问题在这里被掩盖了,因为它以复杂表达式的形式出现//*[@key='xbrl:concept'][. = 'se:Bank'][position() = 1]
,但问题是一样的;你想要的是 (//*[@key='xbrl:concept'][. = 'se:Bank'])[position() = 1]
,或者更简洁地说 (//*[@key='xbrl:concept'][. = 'se:Bank'])[1]
.