我正在两种不同格式之间从xml转换为xml。
我的问题:
如何选择代码为“B”的子字段序列,该代码为“A”的后续兄弟,而不是任何其他字段的代码。
如果有人可以帮我弄清楚如何“选择”正确的节点
限制:
- XSLT 1.0
- 我无法更改数据字段中内容的顺序和由于
不同职位的数量。根据前后子字段应用不同的规则集
- 我不能使用特定的位置(不保证2个子场
'B'将遵循'A'或类似的)
例:
每个帖子都包含具有任意数量子字段的数据字段。
XML与此类似
<datafield tag="1">
<subfield code="A"></subfield>
<subfield code="B"></subfield>
<subfield code="B"></subfield>
<subfield code="C"></subfield>
<subfield code="D"></subfield>
<subfield code="B"></subfield>
<subfield code="B"></subfield>
<subfield code="G"></subfield>
</datafield>
我的xslt:
<xsl:template match="datafield[@tag=1]">
<xsl:choose>
<datafield>
<xsl:attribute name="tag">new tag</xsl:attribute>
<!-- Do not transfer subfield code='X' -->
<xsl:for-each select="./subfield[@code != 'X']">
<subfield>
<xsl:choose>
<xsl:when test="./@code = 'A'">
<xsl:attribute name="code">New code</xsl:attribute>
<!-- Find siblings with the code 'B'.PROBLEM all fields with the code B is selected-->
<xsl:when test="./following-sibling::subfield[@code='B']"> Apply operation here </xsl:when>
</xsl:choose>
</xsl:when>
</xsl:choose>
</subfield>
</xsl:if>
</xsl:for-each>
</datafield>
</xsl:when>
</xsl:choose>
我是一个非常新的stackoverflow用户,所以如果我错过了任何重要的输入,请告诉我并添加它。
答案 0 :(得分:0)
最直接的方法是根据计数做一些事情 - 选择所有以下的B,其前面的非Bs的数量与前面的非Bs加上一个 my 的数量相同(即我)
following-sibling::subfield[@code='B']
[count(preceding-sibling::subfield[not(@code='B')])
= count(current()/preceding-sibling::subfield[not(@code='B')]) + 1]
更有效的方法可能是定义一个键将Bs按其最近的前一个非B分组
<xsl:key name="BbyNonB" match="subfield[@code='B']"
use="generate-id(preceding-sibling::subfield[not(@code='B')][1])" />
然后您可以使用
立即提取当前(非B)子字段后面的所有Bkey('BbyNonB', generate-id())
答案 1 :(得分:0)
伊恩的回答非常棒。我根本不反对。但就个人而言,我发现在递归函数方面学习XSLT更容易。如果您也是这种情况,请考虑此解决方案。同样,作为初学者,在函数调用方面进行思考对我来说更容易。但伊恩的回答显然更短更冷。
这是XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="subfield[@code='A']">
<xsl:for-each select=".">
<xsl:call-template name="getB">
<xsl:with-param name="nodes" select="./following-sibling::subfield"/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="getB">
<xsl:param name="nodes"/>
<xsl:choose>
<xsl:when test="$nodes[1][@code='B']">
<xsl:copy-of select="$nodes[1]"/>
<xsl:call-template name="getB">
<xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
对于此输入:
<datafield tag="1">
<subfield code="A"></subfield>
<subfield code="B"></subfield>
<subfield code="B"></subfield>
<subfield code="C"></subfield>
<subfield code="D"></subfield>
<subfield code="B"></subfield>
<subfield code="B"></subfield>
<subfield code="G"></subfield>
</datafield>
你得到这个输出:
<?xml version="1.0" encoding="utf-8"?>
<subfield code="B"/>
<subfield code="B"/>
但如果这种解决方案无济于事,那就完全忽略它。