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>

Fiddle

或者更简单,将这些节点传递给 head

<xsl:template match="//*[@key='facts']">
    <xsl:value-of select="head(//*[@key='xbrl:concept'][. = 'se:Bank']/../*[@key='heading'])"/>
</xsl:template>

Fiddle

不要使用 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].