我正在尝试使用previous-sibling和following-sibling以及对它们进行排序的记录子集。上一个/后一个从原始xml顺序返回值的问题:
<Salaries>
<Salary>
<Base>1000</Base>
<CreatedDate xmlns:d7p1="http://schemas.datacontract.org/2004/07/System">
<d7p1:DateTime>2016-01-09T14:38:54.8440764Z</d7p1:DateTime>
<d7p1:OffsetMinutes>0</d7p1:OffsetMinutes>
</CreatedDate>
</Salary>
<Salary>
<Base>2000</Base>
<CreatedDate xmlns:d7p1="http://schemas.datacontract.org/2004/07/System">
<d7p1:DateTime>2015-01-09T14:38:54.8440764Z</d7p1:DateTime>
<d7p1:OffsetMinutes>0</d7p1:OffsetMinutes>
</CreatedDate>
</Salary>
<Salary>
<Base>3000</Base>
<CreatedDate xmlns:d7p1="http://schemas.datacontract.org/2004/07/System">
<d7p1:DateTime>2017-01-09T14:38:54.8440764Z</d7p1:DateTime>
<d7p1:OffsetMinutes>0</d7p1:OffsetMinutes>
</CreatedDate>
</Salary>
</Salaries>
当我在for-each(Salaries / Salary)下使用ac#函数将偏移分钟添加到日期并转换为长号201701010000时(在xslt中进行操作更容易)。
<xsl:sort select="number(cs:Convertdatetolong(cs:AddOffsetMinutes(substring(p:CreatedDate/d5p1:DateTime,1,19),p:CreatedDate/d5p1:OffsetMinutes)))" order="ascending"/>
排序完美,我按以下顺序输出记录:
如果我使用previous-sibling / preceding(和follow),问题就来了。我希望第一个记录(2000)没有前面的记录,最后一个记录(3000)没有跟随。 但是当我使用前面/后面的时候,我得到了原始XML中的上一条记录和下一条记录:
我希望能够与之前的记录(按排序顺序)和当前记录(按排序顺序)进行比较:
我已经尝试过前兄弟和前面的
<xsl:value-of select="preceding::p:Salary[1]/p:Base"/>
<xsl:value-of select="preceding-sibling::p:Salary[1]/p:Base"/>
<xsl:value-of select="preceding::p:Salary[position()=1]/p:Base"/>
(薪水位于不同的命名空间(p) 这实际上是可行的,还是我必须使用变量来保存先前记录的数据以进行比较?
感激地收到任何想法。我正在使用xslt 1.0
答案 0 :(得分:1)
preceding-sibling
轴以文档顺序获取上下文节点的前一个兄弟节点。
要在排序之后引用节点的前面兄弟节点,您需要首先将排序的节点存储在变量中 - 并且在XSLT 1.0中,将变量转换为节点集。
答案 1 :(得分:1)
虽然XSLT / XPath经常讨论节点序列&#34;但实际上它更准确地将其视为节点引用序列&#34; - 因为,例如,同一节点可能在序列中出现多次。对一系列节点引用进行排序时,不能以任何方式更改各个节点,只需更改顺序。这意味着节点在原始树中仍然存在于以前的位置,并且它们的父母,兄弟姐妹和后代与之前完全一样。
你想要的不是节点的前后兄弟节点,而是排序顺序中前后的节点,这是完全不同的事情。
执行此操作的一种方法是构造一个包含原始节点副本的新树,例如,如果您这样做
<xsl:variable name="x">
<xsl:for-each ...>
<xsl:sort ...>
<xsl:copy-of select="."/>
复制节点的兄弟关系将反映排序顺序。还有一个小问题,在XSLT 1.0中,$ x是一个结果树片段,所以你必须使用exslt:node-set()函数将它转换为节点集。
事实上在XSLT 1.0中,这可能是唯一的方法,因为XSLT 1.0数据模型只有节点集,而不是序列,这意味着无法捕获和处理节点序列文件订单以外的任何内容。 2.0模型具有更大的灵活性和强大功能。如果可以升级 - XSLT 1.0即将接近20年。
答案 2 :(得分:1)
感谢Michael的回答。在这里发布完整性。因为xml中使用了名称空格而变得复杂:
<!-- Puts the whole of the Salary Node into a variable-->
<xsl:variable name="SALARY" >
<xsl:copy-of select="p:Salaries" />
</xsl:variable>
<!-- Puts the the required key data into a node-set with the correct sort applied-->
<xsl:variable name="SAL">
<xsl:for-each select="msxsl:node-set($SALARY)//p:Salary">
<xsl:sort select="number(cs:Convertdatetolong(cs:AddOffsetMinutes(substring(p:CreatedDate/d5p1:DateTime,1,19),p:CreatedDate/d5p1:OffsetMinutes)))" order="ascending"/>
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
<!-- Quick Output-->
<xsl:for-each select="msxsl:node-set($SAL)//p:Salary">
<xsl:text>Sa:</xsl:text>
<xsl:value-of select="position()" />
<xsl:text>Preceding:</xsl:text>
<xsl:value-of select="preceding-sibling::p:Salary[1]/p:Base"/>
<xsl:value-of select="$newline" />
<xsl:text>Current:</xsl:text>
<xsl:value-of select="p:Base"/>
<xsl:value-of select="$newline" />
<xsl:text>Following:</xsl:text>
<xsl:value-of select="following-sibling::p:Salary[1]/p:Base"/>
<xsl:value-of select="$newline"/>
</xsl:for-each>