xslt < key 使用 ="position()"../> 问题

标签 xslt

我有一个(非常像 excel 电子表格......)xml 数据,我应该从中创建一个更具可读性的数据。
我的标题位于结构的顶部,并且希望根据其文本值创建元素并将它们应用到文档的其余部分。

可能实际数据更清楚,所以我的输入文档看起来像

<?xml version="1.0"?>
<root>
    <headers>
        <header>line</header>
        <header>product</header>
        <header>order</header>
        <header>qty</header>
        <header>deadline</header>
    </headers>
    <row>
        <data>2</data>
        <data>HU12_SETUP</data>
        <data>16069061</data>
        <data>1</data>
        <data>2011-04-13T09:22:59.980</data>
    </row>
    <row>
        <data>1</data>
        <data>40PFL7605H/12</data>
        <data>16310360</data>
        <data>200</data>
        <data>2011-04-13T09:22:59.980</data>
    </row>
</root>

我的目标是拥有一个 xml 文档:

<?xml version="1.0"?>
<morning>
    <row>
        <line>2</line>
        <product>HU12_SETUP</product>
        <order>16069061</order>
        <qty>1</qty>
        <deadline>0</deadline>
    </row>
    <row>
        <line>1</line>
        <product>40PFL7605H/12</product>
        <order>16310360</order>
        <qty>200</qty>
        <deadline>77</deadline>
    </row>
</morning>

我想以“正确”/“有效”的方式做到这一点,这就是为什么我向你们求助,伙计们,来帮助我。
我认为使用 keydata 位置与 header 位置匹配将是我的解决方案,但由于某种原因它不起作用(我'已经~X()。

我需要指出我的 xsl 有什么问题,和/或如果 key 概念有问题,请告诉我更好的解决方案。

这是我的(调试)xsl:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="header" match="header" use="position()" />

    <xsl:template match="/">
        <morning>
            <xsl:apply-templates />
        </morning>
    </xsl:template>
    <xsl:template match="headers" />
    <xsl:template match="row">
        <xsl:copy>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="data">
        <xsl:element name="{concat('bla-',position())}">
            <xsl:value-of select="key('header',position())" />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

我验证position()实际上是正确的。

我的输出因我使用的样式表版本而异。

输出1.0:

<?xml version='1.0' encoding='UTF-8' ?>
<morning>
  <row>
    <bla-1>line</bla-1>
    <bla-2/>
    <bla-3/>
    <bla-4/>
    <bla-5/>
  </row>
  <row>
    <bla-1>line</bla-1>
    <bla-2/>
    <bla-3/>
    <bla-4/>
    <bla-5/>
  </row>
</morning>

输出2.0:

<?xml version='1.0' encoding='UTF-8' ?>
<morning>
  <row>
    <bla-1>line product order qty deadline</bla-1>
    <bla-2/>
    <bla-3/>
    <bla-4/>
    <bla-5/>
  </row>
  <row>
    <bla-1>line product order qty deadline</bla-1>
    <bla-2/>
    <bla-3/>
    <bla-4/>
    <bla-5/>
  </row>
</morning>

如您所见,key('header',position()) 在除第一种情况之外的所有情况下都给我空字符串(这就是为什么我将其作为值,而不是元素名称)。

非常感谢您的帮助,提前谢谢您!

添加:
根据@LarsH 和@Alejandro 的回答(仍然坚持这个关键 事情...)我想出了:

<xsl:template match="data">
    <xsl:variable name="posn" select="position()" />
    <xsl:element name="{key('header',1)[$posn]}" />
    <xsl:element name="{key('header',1)[position()]}" />
</xsl:template>

我可以看到,在这里使用带有静态 1 的键是愚蠢的,但我很害怕为什么上面的两个结果元素不匹配?
第一个是正确的,第二个总是给我 linelineproductorderqtydeadline 返回。

有人能给我指出正确的方向吗?

最佳答案

XSLT 1.0 和 2.0 之间的输出差异在于,在 1.0 中,xsl:value-of 输出所选节点集中的第一个节点的字符串值,而(IIRC)在2.0中,它输出所选节点集中所有节点的串联值,以空格作为默认分隔符。 (不过,在你相信我之前请先检查一下。)

因此,根据您的输出,每个 header 元素的键值似乎始终为 1。我不确定使用时 position() 会产生什么结果在键的 use 属性中(它以我没有查找过的方式取决于上下文),所以这对我来说是合理的。

我会尝试以下方法,而不是使用带有 position() 的键:

 <xsl:key name="header" match="header"
          use="count(preceding-sibling::header) + 1" />

这有效。如果您有数千个 header ,它可能会很慢,但我认为您永远不会。

或者,您可以决定不使用 key ,而是使用

<xsl:template match="data">
    <xsl:variable name="posn" value="position()" />
    <xsl:element name="{concat('bla-', $posn)}">
        <xsl:value-of select="/root/headers/header[$posn]" />
    </xsl:element>
</xsl:template>

通常使用键是为了获得更好的性能,但在这种情况下,似乎不清楚与使用 [$posn] 谓词相比是否会有任何显着的性能优势。

添加:

上面“添加”的答案足够长,需要放在这里而不是评论。在您的补充中:

<xsl:template match="data">
    <xsl:variable name="posn" select="position()" />
    <xsl:element name="{key('header',1)[$posn]}" />
    <xsl:element name="{key('header',1)[position()]}" />

正如我的评论中所述,上下文包括当前节点当前节点列表。对于第一个 position(),在变量的选择中,当前节点列表由属于 row 子级的所有 data 元素组成> 正在处理的元素。因此,position() 生成该列表中当前节点(data 元素)的位置。该值存储在 $posn 变量中。

key('header',1) 生成所有 header 元素的节点列表,原因如上所述:每个 header 的键值code> 始终为 1。因此 key('header',1)[$posn] 给出第 n 个 header 元素,其中 n 是当前数据元素在其兄弟元素中的位置。

对于第二个 position() 调用:在谓词中,上下文是通过将谓词单独应用于由 XPath 表达式生成的节点列表中的每个节点来确定的,直到该点为止节点列表作为当前节点列表。所以在key('header',1)[...]的方括号内,上下文节点列表就是key('返回的节点列表 header ',1)。同样,这是所有 header 元素的列表。因此,对于每个 header 元素,position() 此处返回该 header 在其同级元素中的位置。

现在我们更深入一点...谓词本质上是 bool 值,但是当谓词中的表达式 e 是数字时,它被视为 position() = 的缩写e。所以你的第二个元素名称表达式相当于

    <xsl:element name="{key('header',1)[position() = position()]}" />

并且 position() =position() 对于任何给定上下文始终为 true,因此上面等价于

    <xsl:element name="{key('header',1)}" />

这是所有 header 的列表。

关于xslt < key 使用 ="position()"../> 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5874376/

相关文章:

ruby-on-rails - exslt 功能在 ruby​​-xslt gem 中不起作用

node.js - 根据接收器文件中的条件填充 Node

xml - 尝试创建通用 XSL 以允许略有不同的 XML 格式

xml - XSL 使用计数器反转顺序

xml - 对源 XML 文档的多个小更改

xml - XSLT 处理元素的第一次出现

xml - 使用 XSL-FO 在 PDF 中添加换行符?

xslt - XSLT在同一路径上添加元素

xslt - 我想选择一个节点下的所有文本(包括节点名称)

xslt - 使用 XSL 缩进 XML