XSLT for-each,正在尝试创建 header-line 结构

XSLT for-each, trying to create header-line structure

这不是浏览器类型 XSLT,这是用于处理数据 (SAP B1 Integration Framework)。假设我们有两个 SQL 表,HEADER 和 LINE,我们希望避免我们首先从 HEADER SELECT 然后启动单独的 [=32] 的工作=] 对于每行,因为这需要“可视化编程”,我们更喜欢编写代码而不是连接箭头。所以我们向服务器发送一个类似 SELECT * FROM HEADER, SELECT * FROM LINES 的查询,我们得到一个 XML 大致如下:

<ResultSets>
<ResultSet>
    <Row><MHeaderNum>1</MHeaderNum></Row>
    <Row><MHeaderNum>2</MHeaderNum></Row>
    <Row><MHeaderNum>3</MHeaderNum></Row>
</ResultSet>

<ResultSet>
    <Row><LineNum>1</LineNum> <HeaderNum>1</HeaderNum></Row>
    <Row><LineNum>2</LineNum> <HeaderNum>2</HeaderNum></Row>
    <Row><LineNum>1</LineNum> <HeaderNum>3</HeaderNum></Row>
    <Row><LineNum>2</LineNum> <HeaderNum>1</HeaderNum></Row>
    <Row><LineNum>1</LineNum> <HeaderNum>2</HeaderNum></Row>
    <Row><LineNum>2</LineNum> <HeaderNum>3</HeaderNum></Row>
</ResultSet>

所以我们认为我们是命令式的程序程序员并且拉

<xsl:for-each select="//ResultSets/Resultset[1]/Row">
   do stuff with header data
   <xsl:for-each select="//ResultSets/Resultset[2]/Row[HeaderNum=MHeaderNum]">
      do stiff with the line data beloning to this particular header
   </xsl:for-each>  
</xsl:for-each>

当然,这不会闪烁,因为 MHeaderNum 脱离了上下文,就像 grunge 过时了,我们也不能将它保存到变量中,因为我们不会更新该变量,因为 XSLT 是某种东西一种不可变的函数式编程语言。

但是不要害怕,一个内心的声音说,因为 XSLT 专家可以使用模板解决类似的问题。模板,如果我理解的话,是某种 XSLT 的功能。它们可以是递归的,诸如此类。那么它们可以用来解决这样的问题吗?

当然我们谈论的是 XSLT 1.0,因为我不知道 Java 是否曾经费心实施更高版本,但 SAP 肯定没有费心去使用所说的假设实施。

或者我真的应该忘记这个,只连接我的视觉箭头吗?问题是,SQL 不应该在这样的迭代中使用 headers 然后通过行方式迭代。我想做的是让 SQL 数据库变得快乐,从中获取大量数据,然后在其他地方处理它,而不是用七十亿个小查询来打扰它。在我们的例子中,可悲的是其他地方是 XSLT,虽然从技术上讲我可以尝试 JavaScript 以及 SAP 也为这堆混乱添加了一个 Nashorn,但也许它可以在“纯”XSL 中解决?

您可以试试下面的 XSLT。它使用三个 XSLT 模板。

由于所需的输出未知,我对每个页眉和行项目模板进行了一些任意处理。

XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>

    <xsl:template match="/ResultSets/ResultSet[1]">
        <ResultSet1>
            <xsl:for-each select="Row">
                <r>
                    <xsl:value-of select="MHeaderNum"/>
                </r>
            </xsl:for-each>
        </ResultSet1>
    </xsl:template>

    <xsl:template match="/ResultSets/ResultSet[2]">
        <ResultSet2>
            <xsl:for-each select="Row">
                    <xsl:copy-of select="."/>
            </xsl:for-each>
        </ResultSet2>
    </xsl:template>
</xsl:stylesheet>

无论是 XSLT 1 还是更高版本以及是否使用模板和 for-each,current() 函数都存在://ResultSets/Resultset[2]/Row[HeaderNum=current()/MHeaderNum].

解决交叉引用的最佳方法是使用 key.
例如,以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="line-by-header" match="ResultSet[2]/Row" use="HeaderNum" />

<xsl:template match="/ResultSets">
    <output>    
        <xsl:for-each select="ResultSet[1]/Row">
            <header num="{MHeaderNum}"> 
                <xsl:for-each select="key('line-by-header', MHeaderNum)">
                    <line>
                        <xsl:value-of select="LineNum"/>
                    </line>
                </xsl:for-each>
            </header>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

应用于以下输入时:

XML

<ResultSets>
    <ResultSet>
        <Row><MHeaderNum>1</MHeaderNum></Row>
        <Row><MHeaderNum>2</MHeaderNum></Row>
        <Row><MHeaderNum>3</MHeaderNum></Row>
    </ResultSet>
    <ResultSet>
        <Row><LineNum>1</LineNum> <HeaderNum>1</HeaderNum></Row>
        <Row><LineNum>2</LineNum> <HeaderNum>2</HeaderNum></Row>
        <Row><LineNum>3</LineNum> <HeaderNum>3</HeaderNum></Row>
        <Row><LineNum>4</LineNum> <HeaderNum>1</HeaderNum></Row>
        <Row><LineNum>5</LineNum> <HeaderNum>2</HeaderNum></Row>
        <Row><LineNum>6</LineNum> <HeaderNum>3</HeaderNum></Row>
    </ResultSet>
</ResultSets>

将 return:

结果

<?xml version="1.0" encoding="UTF-8"?>
<output>
  <header num="1">
    <line>1</line>
    <line>4</line>
  </header>
  <header num="2">
    <line>2</line>
    <line>5</line>
  </header>
  <header num="3">
    <line>3</line>
    <line>6</line>
  </header>
</output>