我只想使用 XSLT 1.0 来解析这种 XML:
<root>
<Block id="1" inputPorts="2" outputPorts="3" />
<OutputPort id="2" parent="1" /> <!-- first OutputPort after Block so current = 0, should give coordinate(0,3) = 1/6 -->
<InputPort id="3" parent="1" /> <!-- first InputPort after Block so current = 0, should give coordinate(0,2) = 1/4 -->
<OutputPort id="4" parent="1" /> <!-- second OutputPort after Block so current = 1, should give coordinate(1,3) = 3/6 -->
<InputPort id="5" parent="1" /> <!-- second InputPort after Block so current = 1, should give coordinate(1,2) = 3/4 -->
<OutputPort id="6" parent="1" /> <!-- third OutputPort after Block so current = 2, should give coordinate(2,3) of 5/6 -->
<Block id="7" inputPorts="0" outputPorts="1" />
<OutputPort id="8" parent="7" /> <!-- first OutputPort after Block so current = 0, should give coordinate(0,1) = 1/2 -->
</root>
有多个Block
标签。InputPort
和OutputPort
标签以任意顺序跟在Block
标签之后,按照 属性中可用的数字排序Block
。但是,它们位于下一个Block
标签之前。
输出应该是这样的:
<root>
<Block id="1" inputPorts="2" outputPorts="3" />
<OutputPort id="2" parent="1" coordinate="0.1666" />
<InputPort id="3" parent="1" coordinate="0.25" />
<OutputPort id="4" parent="1" coordinate="0.5" />
<InputPort id="5" parent="1" coordinate="0.75" />
<OutputPort id="6" parent="1" coordinate="0.8333" />
<Block id="7" inputPorts="0" outputPorts="1" />
<OutputPort id="8" parent="7" coordinate="0.5" />
</root>
每个端口的位置取决于端口号和端口总数。基本公式为:
coordinate(current, total) = (2 * current + 1) / (2 * total)
如何获取模板中的current
和的值?total
每个Block
、InputPort
和OutputPort
标签都有自己的模板。
我尝试过使用全局变量。但是,我发现在 XSLT 1.0 中无法全局重新分配全局变量。我们可以在模板内部重新分配新值,但这在其他模板中甚至在调用不同标签的同一模板中都没有用。这是我使用全局变量的解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="inputPorts" value="0" />
<xsl:variable name="outputPorts" value="0" />
<xsl:variable name="currentInputPort" value="0" />
<xsl:variable name="currentOutputPort" value="0" />
<xsl:output method="xml" indent="no" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="comment()" />
<xsl:template match="Block">
<xsl:copy>
<xsl:variable name="inputPorts">
<xsl:value-of select="@inputPorts" />
</xsl:variable>
<xsl:variable name="outputPorts">
<xsl:value-of select="@outputPorts" />
</xsl:variable>
<xsl:variable name="currentInputPort" value="0" />
<xsl:variable name="currentOutputPort" value="0" />
<xsl:attribute name="id">
<xsl:value-of select="@id" />
</xsl:attribute>
<xsl:attribute name="inputPorts">
<xsl:value-of select="@inputPorts" />
</xsl:attribute>
<xsl:attribute name="outputPorts">
<xsl:value-of select="@outputPorts" />
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="InputPort">
<xsl:copy>
<xsl:attribute name="id">
<xsl:value-of select="@id" />
</xsl:attribute>
<xsl:attribute name="parent">
<xsl:value-of select="@parent" />
</xsl:attribute>
<xsl:attribute name="coordinate">
<xsl:value-of select="(2 * $currentInputPort + 1) div (2 * $inputPorts)" />
</xsl:attribute>
<xsl:variable name="currentInputPort" select="$currentInputPort + 1" />
</xsl:copy>
</xsl:template>
<xsl:template match="OutputPort">
<xsl:copy>
<xsl:attribute name="id">
<xsl:value-of select="@id" />
</xsl:attribute>
<xsl:attribute name="parent">
<xsl:value-of select="@parent" />
</xsl:attribute>
<xsl:attribute name="coordinate">
<xsl:value-of select="(2 * $currentOutputPort + 1) div (2 * $outputPorts)" />
</xsl:attribute>
<xsl:variable name="currentOutputPort" select="$currentOutputPort + 1" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
(已编辑)
也许类似这样的方法对你有用。它分两步进行,以实现每个块的重新编号:
使用您更正的 XML 输入将返回:
如果可以接受按类型分组输出块的端口,则可以一次性执行转换:
XSLT 1.0
结果