xslt <key use="position()";../>问题 [英] xslt <key use="position()" ../> problem

查看:16
本文介绍了xslt <key use="position()";../>问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个(非常像 excel 电子表格)xml 数据,我应该从中创建一个更易读的数据.
我在结构顶部有标题,并且想从它们的文本值创建 elements 并将它们应用于文档的其余部分.

I've got a (very excel spreadsheet like..) xml data, from which I'm supposed to create a more readable one.
I have the headers on the top of the structure, and would like to create elements from their text value and apply them on the rest of the document.

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

Probably the actual data speaks clearer, so my input document looks like

<?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 文档:

and my goal is to have an xml document as:

<?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( ).

I'd like to do this in a "proper" / "efficient" way, that's why I'm turning to you, guys, to help me out.
I figured using a key to match data positions to header positions would be my solution, but for some reason it just doesn't work (I'am already ~X( ).

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

What I need is to point out what is wrong with my xsl, and/or if there's something wrong with the key concept, advise me better solution.

这是我的(调试)xsl:

Here is my (debugging) 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() 实际上是正确的.

where I verify that the position() is actually correct.

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

My output varies depending on which stylesheet version I use.

输出 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()) 在除第一种情况之外的所有情况下都给我空字符串(这就是为什么我将它作为值,而不是元素名称).

As you can see, key('header',position()) gives me empty string in all the cases except the first (that's why i have it as value, not element name).

我将不胜感激,在此先感谢您!

I would appreciate any help, thank you in advance!

添加:
基于@LarsH 和@Alejandro 的回答(仍然坚持这个 key 事情......)我想出了:

Addition:
Based on @LarsH's and @Alejandro's answer (still stuck to this key thing...) I came up with:

<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 的键是愚蠢的,但我很害怕为什么从那里产生的两个结果元素不匹配?
第一个是正确的,第二个总是给我line,分别返回lineproductorderqtydeadline.

I can see that using a key here with a static 1 is dumb, but I'm getting scared why the two resulting elements from up there do not match?
The first is correct, the second always gives me line, respectively lineproductorderqtydeadline back.

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

Could anyone point me to the right direction?

推荐答案

XSLT 1.0 和 2.0 在输出上的区别在于,在 1.0 中,xsl:value-of 输出的是 xsl:value-ofem>first 节点集中的节点,而2.0中的(IIRC)则输出选择节点集中所有节点的连接值,空格作为默认分隔符.(在你相信我之前检查一下.)

The difference in output between XSLT 1.0 and 2.0 is that in 1.0, xsl:value-of outputs the string value of the first node in the selected nodeset, whereas (IIRC) in 2.0, it outputs the concatenated values of all the nodes in the selected nodeset, with space as the default delimiter. (Check on that before you believe me though.)

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

So based on your output, it looks like the key value for each header element is always 1. I'm not sure what position() would yield when used in the use attribute of a key (it depends on the context in a way that I haven't looked up), so that's plausible to me.

与其使用带有 position() 的键,我会尝试以下操作:

Rather than using a key with position(), I would try something like:

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

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

This works. It might be slow if you had thousands of headers, but I assume you never would.

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

Alternatively, you could decide not to use keys, and instead do

<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] 谓词相比,似乎不清楚是否会有任何显着的性能优势.

Usually keys are used for better performance, but in this case it seems unclear that there would be any significant performance advantage vs. using the [$posn] predicate.

添加:

上面添加"的答案已经足够长,需要在这里而不是评论.另外:

The answer to your "addition" above is long enough it needs to be in here rather than a comment. In your addition:

<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(),在变量的 select 中,当前节点列表包含所有 data 元素,它们是 row 的子元素> 正在处理的元素.所以 position() 产生了 当前节点(一个 data 元素)在该列表中的位置.该值存储在 $posn 变量中.

As stated in my comment, the context includes both the current node and the current node list. For the first position(), in the select of the variable, the current node list consists of all the data elements that are children of the row element being processed. So position() yields the position of the current node (a data element) in that list. This value is stored in the $posn variable.

key('header',1) 生成所有 header 元素的节点列表,原因如上所述:每个 header 总是 1.所以 key('header',1)[$posn] 给出了 nth 头元素,其中 n 是当前数据元素在其同级中的位置.

key('header',1) yields a node list of all header elements, for reasons explained above: the key value for each header is always 1. So key('header',1)[$posn] gives the nth header element, where n is the position of the current data element among its siblings.

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

For the second position() call: In a predicate, the context is determined by applying the predicate individually to each node in the node list produced by the XPath expression up to that point, with that node list as the current node list. So inside the square brackets of key('header',1)[...], the context node list is the node list returned by key('header',1). Again, this is the list of all header elements. So for each header element, position() here returns the position of that header among its siblings.

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

Now we get a little deeper... Predicates are boolean by nature, but when the expression e in a predicate is numeric, it is treated as an abbreviation for position() = e. So your second element name expression is equivalent to

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

position() = position() 对于任何给定的上下文总是为真,所以上面的等价于

and position() = position() is always true for any given context, so the above is equivalent to

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

这是所有标题的列表.

这篇关于xslt &lt;key use="position()";../>问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆