(XSLT,代码优化)如何输出引用兄弟节点值的节点..?
我正在使用 XSLT 将 XML 转换为 XML,目的是读取标签
的值,如果它为 null,则必须为其分配
,如果
也为 null,则必须为两个标签分配默认文本“Default”..
编辑:如果
为空并且
不是..那么代码不应更新
带有 'Default'
文本,但必须按原样进行转换..
这是我正在尝试使用的测试 XML:
<root>
<node1></node1>
<node2></node2>
<parent>
<node1>data1</node1>
<node2></node2>
</parent>
<parent>
<node1></node1>
<node2>data2</node2>
</parent>
<parent>
<node1>data1</node1>
<node2>data2</node2>
</parent>
</root>
这是我的 XSLT 代码设计过:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="template1" match="node2[(following-sibling::node1[.='']|preceding-sibling::node1[.=''])]">
<xsl:choose>
<xsl:when test=".=''">
<node1><xsl:text>Default</xsl:text></node1>
<node2><xsl:text>Default</xsl:text></node2>
</xsl:when>
<xsl:otherwise>
<node1>
<xsl:value-of select="text()"/>
</node1>
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="template2" match="node1[.='']"/>
虽然我的代码可以工作,但我对其代码的庞大程度并不满意..有没有办法摆脱多余的(如果有的话)行....并且有没有其他方法可以使用2个模板来完成此任务(即template1和template2),是否可以减少模板的数量?
I am transforming XML to XML using XSLT, The objective is to read the value of tag <node1>
, if it is null then it must be assigned with the value of <node2>
, if incase <node2>
, is also null, then default text "Default" has to be assigned .. to both tags ..
EDIT: If <node2>
is null and <node1>
isn't .. then the code shouldn't update <node2>
with 'Default'
text but it has to be transformed as it is ..
This is the test XML I am trying with:
<root>
<node1></node1>
<node2></node2>
<parent>
<node1>data1</node1>
<node2></node2>
</parent>
<parent>
<node1></node1>
<node2>data2</node2>
</parent>
<parent>
<node1>data1</node1>
<node2>data2</node2>
</parent>
</root>
And this the XSLT code I have designed:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="template1" match="node2[(following-sibling::node1[.='']|preceding-sibling::node1[.=''])]">
<xsl:choose>
<xsl:when test=".=''">
<node1><xsl:text>Default</xsl:text></node1>
<node2><xsl:text>Default</xsl:text></node2>
</xsl:when>
<xsl:otherwise>
<node1>
<xsl:value-of select="text()"/>
</node1>
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="template2" match="node1[.='']"/>
Though my code works, I am not happy with its bulkiness of the code .. Is there anyway to get rid of redundant (if any) lines .... And is there any alternative to use 2 templates to accomplish this (namely template1 and template2), is it possible to reduce the number of templates?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我。 XSLT 1.0 解决方案:
它比当前解决方案更短、更简单 -- 比当前选择的解决方案少了 7 行,更重要的是,少了一个模板。
更重要的是,该解决方案是完全声明式和推送式的 - 不调用命名模板,唯一的
位于身份规则中。二. XSLT 2.0 解决方案
利用 XPath 2.0 序列的强大功能,该解决方案比 XSLT 1.0 解决方案要短得多。
类似的事情在 XSLT 1.0 中是不可能的(例如选择两个节点并集的第一个而不指定谓词以使两个节点互斥),因为具有默认文本的节点和 node1/ node2 节点属于不同的文档,众所周知,不同文档的节点之间的节点顺序是特定于实现的,并且不被保证/规定。
此解决方案是完全声明性的(没有 if/then/else)并且完全是推送风格:唯一的
位于身份规则中。I. XSLT 1.0 solution:
It is shorter and simpler than the current solutions -- 7 lines less and, more importantly, one template less than the currently selected solution.
Even more importantly, this solution is completely declarative and push-style -- no calling of named templates and the only
<xsl:apply-templates>
is in the identity rule.II. XSLT 2.0 solution
Using the power of XPath 2.0 sequences this solution is quite shorter than the XSLT 1.0 solution.
Something similar is not possible in XSLT 1.0 (such as selecting the first of the union of two nodes without specifying predicates to make the two nodes mutually exclusive), because the node with the default text and the node1/node2 nodes belong to different documents and, as we know well, node ordering between nodes of different documents is implementation specific and is not guaranteed/prescribed.
This solution is completely declarative (no if/then/else) and completely push style: the only
<xsl:apply-templates>
is in the identity rule.我已经修改了 Tomalak的回答并完成了要求..
正如我在问题中提到的,如果兄弟节点 1 不为空(并且如果没有兄弟节点 1),则此代码将节点 2 作为空传递(如果它为空)。
这段代码最终成为我的代码的替代方案已发布在我的问题中..(我并不是说它足够完美..但我很高兴我可以尝试..:-)
这段代码比我的代码效率高了大约 10-20 毫秒..:-)
就这样..
I have modified Tomalak's answer and accomplished the requirement ..
As I have mentioned in my question, This code passes node2 as null (if it is null) if the sibling node1 isn't null (and also if there is no sibling node1) ..
This code finally became an alternative to the one I have posted in my Q .. (I don't say it is perfect enough .. but I am glad that I could try .. :-)
And this code is more efficient than mine by some 10-20 msecs .. :-)
Here it goes ..
使用 XSLT 2.0 我会这样做,但无论如何你的更容易阅读。
Using XSLT 2.0 I would do this, but yours is easier to read anyway.