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>
这不是浏览器类型 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>