当前位置 : 主页 > 网页制作 > xml >

xml – (XSLT,代码优化)如何输出引用兄弟节点值的节点..?

来源:互联网 收集:自由互联 发布时间:2021-06-13
我正在使用XSLT将 XML转换为 XML,目标是读取标记 node1的值,如果它为null,则必须为其分配 node2的值,如果incase node2,也是null,然后必须为两个标签分配默认文本“Default”.. 编辑:如果 node2为空
我正在使用XSLT将 XML转换为 XML,目标是读取标记< node1>的值,如果它为null,则必须为其分配< node2>的值,如果incase< node2>,也是null,然后必须为两个标签分配默认文本“Default”..
编辑:如果< node2>为空且< node1>不是..那么代码不应该更新< node2>使用“默认”文本但必须按原样进行转换..

这是我正在尝试的测试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. XSLT 1.0解决方案:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:variable name="vReplacement">Default</xsl:variable>

       <xsl:variable name="vRep" select=
        "document('')/*/xsl:variable[@name='vReplacement']/text()"/>

     <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
     </xsl:template>

     <xsl:template match="node1[not(node())] | node2[../node1[not(node())]]">
      <xsl:copy>
          <xsl:copy-of select="../node2/text() | $vRep[not(current()/../node2/text())]"/>
      </xsl:copy>
     </xsl:template>
</xsl:stylesheet>

它比现有解决方案更短更简单 – 减少7行,更重要的是,比当前选择的解决方案少一个模板.

更重要的是,这个解决方案完全是声明式和推式 – 没有调用命名模板和唯一的< xsl:apply-templates>在身份规则中.

II. XSLT 2.0解决方案

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
 </xsl:template>

 <xsl:template match="node1[not(node())] | node2[../node1[not(node())]]">
  <xsl:copy>
      <xsl:sequence select="(../node2/text(), 'Default')[1]"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

利用XPath 2.0序列的强大功能,此解决方案比XSLT 1.0解决方案短得多.

类似的东西在XSLT 1.0中是不可能的(例如选择两个节点的第一个联合而不指定谓词以使两个节点互斥),因为具有默认文本和node1 / node2节点的节点属于不同的文档和我们知道,不同文档节点之间的节点排序是特定于实现的,不能保证/规定.

这个解决方案完全是声明性的(no if / then / else)和完全推送样式:唯一的< xsl:apply-templates>在身份规则中.

网友评论