我正在两种不同的格式之间从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>
我是一个非常新的堆栈溢出用户,所以如果我错过了任何重要的输入,请告诉我并添加它。
最直接的方法是根据计数做一些事情 - 选择以下所有 B,其前面的非 B 的数量与我前面的非 B 的数量相同加一(即我)
following-sibling::subfield[@code='B']
[count(preceding-sibling::subfield[not(@code='B')])
= count(current()/preceding-sibling::subfield[not(@code='B')]) + 1]
更有效的方法可能是按 B 前面最接近的非 B 定义一个键分组
<xsl:key name="BbyNonB" match="subfield[@code='B']"
use="generate-id(preceding-sibling::subfield[not(@code='B')][1])" />
然后您可以立即提取当前(非 B)子字段之后的所有 B
key('BbyNonB', generate-id())
Ian 的回答真的很棒。我根本不反对这一点。但就我个人而言,我发现从递归函数的角度学习 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"/>
但是,如果这种解决方案没有帮助,请忽略它。