我有一个(非常优秀的电子表格,如...)xml数据,我应该从中创建一个更可读的数据.
我在结构的顶部有标题,并希望elements从其文本值创建并将其应用于文档的其余部分.
可能实际数据说得更清楚,所以我的输入文档看起来像
<?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>
Run Code Online (Sandbox Code Playgroud)
我的目标是将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>
Run Code Online (Sandbox Code Playgroud)
我想以"正确"/"有效"的方式做到这一点,这就是为什么我转向你们,伙计们,帮助我.
我认为使用a key匹配data位置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>
Run Code Online (Sandbox Code Playgroud)
我验证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>
Run Code Online (Sandbox Code Playgroud)
输出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>
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,key('header',position())在除了第一个之外的所有情况下都给我空字符串(这就是为什么我将它作为值,而不是元素名称).
我将不胜感激任何帮助,谢谢!
另外:
基于@ LarsH和@Alejandro的回答(仍然坚持这个key......)我提出:
<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>
Run Code Online (Sandbox Code Playgroud)
我可以看到在这里使用带有静态的键1是愚蠢的,但我害怕为什么那里的两个结果元素不匹配?
第一个是正确的,第二个总是给我line,分别lineproductorderqtydeadline回来.
有人能指出我正确的方向吗?
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" />
Run Code Online (Sandbox Code Playgroud)
这有效。如果您有数千个标头,它可能会很慢,但我认为您永远不会。
或者,您可以决定不使用密钥,而是这样做
<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>
Run Code Online (Sandbox Code Playgroud)
通常使用键是为了获得更好的性能,但在这种情况下,似乎不清楚与使用谓词相比是否会有任何显着的性能优势[$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()]}" />
Run Code Online (Sandbox Code Playgroud)
正如我的评论中所述,上下文包括当前节点和当前节点列表。对于第一个position(),在变量的选择中,当前节点列表由作为正在处理的元素data的子元素的所有元素组成row。因此产生当前节点(元素)在该列表中position()的位置。该值存储在变量中。data$posn
key('header',1)产生所有元素的节点列表header,原因如上所述:每个元素的键值header始终为 1。因此key('header',1)[$posn]给出n第 th 标头元素,其中n是当前数据元素在其兄弟元素中的位置。
对于第二次position()调用:在谓词中,通过将谓词单独应用于由 XPath 表达式生成的节点列表中的每个节点来确定上下文,该节点列表作为当前节点列表。因此,在 的方括号内key('header',1)[...],上下文节点列表是由 所返回的节点列表key('header',1)。同样,这是所有元素的列表header。因此,对于每个header元素,position()这里返回该标头在其同级元素中的位置。
现在我们更深入一点...谓词本质上是布尔值,但是当e谓词中的表达式是数字时,它被视为 的缩写position() = e。所以你的第二个元素名称表达式相当于
<xsl:element name="{key('header',1)[position() = position()]}" />
Run Code Online (Sandbox Code Playgroud)
对于任何给定的上下文总是position() = position()正确的,所以上面等价于
<xsl:element name="{key('header',1)}" />
Run Code Online (Sandbox Code Playgroud)
这是所有标题的列表。