以微弱的努力进行编辑以澄清。系统通过 XSL 处理器将 XML 转换为另一个 XML。
我正在为具有插件卡的机器做一些 XSL 规则的东西。这些卡将向主主机提供它们自己的 XSL 规则,然后主机将这些规则整理成一个超级 XSL 文件,由它自己处理,并发送到已通过 HTTP 连接到机器上的 Web 浏览器。浏览器用于设置机器的配置项,XSL 用于更改和/或隐藏和/或取消隐藏某些 XML。为了简化我的查询,我发明了一个小例子。
当用户将一个项目配置为 B 类型时(选择几个,例如 A、B、C、...),那么接下来的两个项目也将被更改(以某种方式)。在真正的交易中,有一个属性“隐藏”设置为真或假,还有设置的子元素。实物中的下两项将被隐藏,并且子元素也已更改。
当用户将项目从 B 类型更改为 A 类型时,我需要确定哪些其他节点需要将其“隐藏”属性设置为 false。用户将根据他们认为合适的方式更改子元素。
所有这些都是“循环”的,并且是有序的,所以如果一个节点设置为 B 类型,并且它是最后一个节点(没有后续兄弟节点),那么受影响的节点就是集合中的第一个。(在 XPath 术语中,如果节点 [4] 是类型 B,则节点 [1] 和 [2] 将被隐藏和更改)。
所以,对于我这里的例子,我有一个输入 XML:
<topline>
<midline type="A" name="mid1" hidden="false"><source name="off"/></midline>
<midline type="B" name="mid2" hidden="false"><source name="input 1"/></midline>
<midline type="A" name="mid3" hidden="false"><source name="off"/></midline>
<midline type="A" name="mid4" hidden="false"><source name="off"/></midline>
</topline>
XSL 会将其更改为:
<topline>
<midline type="A" name="mid1" hidden="false"><source name="off"/></midline>
<midline type="B" name="mid2" hidden="false"><source name="input 1"/></midline>
<midline type="A" name="mid3" hidden="true"><source name="input 1"/></midline>
<midline type="A" name="mid4" hidden="true"><source name="input 1"/></midline>
</topline>
现在,如果用户改变主意,将 mid2 更改为 A 类:
<topline>
<midline type="A" name="mid1" hidden="false"><source name="off"/></midline>
<midline type="A" name="mid2" hidden="false"><source name="input 1"/></midline>
<midline type="A" name="mid3" hidden="true"><source name="input 1"/></midline>
<midline type="A" name="mid4" hidden="true"><source name="input 1"/></midline>
</topline>
然后 XSL 将取消隐藏 mid2 的循环以下兄弟姐妹,因此结果应该是:
<topline>
<midline type="A" name="mid1" hidden="false"><source name="off"/></midline>
<midline type="A" name="mid2" hidden="false"><source name="input 1"/></midline>
<midline type="A" name="mid3" hidden="false"><source name="input 1"/></midline>
<midline type="A" name="mid4" hidden="false"><source name="input 1"/></midline>
</topline>
这是我正在努力的第二步。对我来说,我为解决这个问题所做的工作相当难看,但考虑到我想要实现的并不是真正的 XSL 友好,这可能是不可避免的。
我做了什么:
<xsl:for-each select="topline">
<xsl:for-each select="midline">
<xsl:variable name="masterPosition" select="position()"/>
<xsl:choose>
<xsl:when test="@type='B'>
hide the next two nodes. This is easy:
translate($masterPosition, '1234', '2341')
works nicely.
</xsl:when>
<xsl:otherwise>
<xsl:variable name="prior1" select="translate(masterPosition, '1234', '4123')"/>
<xsl:variable name="test1" select="../midline[$prior1]/source[1]/@name='off'"/>
this second line doesn't work: I only get the first node, always.
So instead I have
<xsl:variable name="test2">
<xsl:choice>
<xsl:when test="$masterPosition='1'"><xsl:value-of select="../midline[4]/source"/></xsl:when>
and so on for the other masterPositions
</xsl:choice>
</xsl:variable>
and this is repeated for a few other variables, one each for each relevant
prior position and for the fields I need to change. I then use these
variables to change the XML - there's something in the main machine's
processing to enable this, I believe it is non-standard, so please ignore:
(At least it doesn't run against Xalan).
<set key={$test2}/@hidden, value="false")/>
</xsl:otherwise>
</xsl:choose>
<xsl:for-each>
</xsl:for-each>
您能想到一种更优雅的方法吗?如果没有,请不要担心,我相信我的 hack 会起作用,并且也不应该消耗太多 MIPS。
我不能使用<xsl:key>
,因为我们的系统无法处理:我们有多个 XSL 源,它们被整理成一个,整理脚本(我无法控制)根本无法理解<xsl:key>
,所以如果有使用密钥的解决方案,我不能使用它。
谢谢理查德