Xslt - 将节点移动到一个“级别”

时间:2017-11-13 13:44:17

标签: xslt

我想在xml结构中将xml属性提升一级。 至于要求我展示了一个更详细的例子:

<items>
  <kitchen>
    <furnitures>
      <chairs type="wood">
        <chair_1 color="green" legs="4"/>
      </chairs>
      <tables type="stone">
      </tables>
    </furnitures>
  </kitchen>
</items>

我想输出这个:

<items>
  <kitchen>
    <furnitures>
      <chairs type="wood"/>
      <chair_1 color="green" legs="4"/>
      <tables type="stone">
      </tables>
    </furnitures>
  </kitchen>
</items>

如您所见,我将char_1移到

下面
<xsl:template match="node()">
  <xls:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="*"/>
    <xsl:apply-templates select="text()">
  </xsl:copy>
</xsl:template>

<xsl:template match="/items/kitchen/furnitures/chairs">
  <xsl:choose>
    <xsl:when test="chair_1">
      <xsl:copy>
      <xsl:apply-templates select="child::node()[not(self:chair_1)]|@*|text()"/>
      </xsl:copy>
    <xsl:apply-templates select="chair_1"/>
    </xsl:when>
     <!----- edit -->
      <xsl:otherwise>
        <xsl:copy>
          <xls:apply-templates select ="@*|node()"/>
        </xsl:copy>
       <xsl:apply-templates select="settings"/>
       <xsl:text>
       </xsl:text>
       <chair_1 color="green" legs="4"/>
    </xls:otherwise>
  </xls:choose>
</xsl:template>

所以,我的主要问题是,我的副本不包含换行符。 请记住,我正在使用PHP:Xsltproc,在我的dev-comp上缩进工作正常,但是使用PHP的xsltproc它不好,并删除换行符。 所以输出如下:

<items>
  <kitchen>
    <furnitures>
      <chairs type="wood"/><chair_1 color="green" legs="4"/>
      <tables type="stone">
      </tables>
    </furnitures>
  </kitchen>
</items>

哪个好,但没有正确缩进。 (免责声明:可能有一些拼写错误,因为这不是原始的XML,当然我使用所需的样式表,版本,phpversion,xml版本标签,当然我的输出方法是xml和indent =“是”)

更新: 当我有第二个“WHEN”时,(如果没有chair_1)我想把它“粘贴”到代码中。但缩进失败,它使整个副本成一行。可能是什么问题?

1 个答案:

答案 0 :(得分:1)

您提供的模板不会影响您所说的转换,至少不会影响它们自己。实际上,它们甚至都不是有效的XSL。

在纠正明显的语法错误之后,匹配node()的结果模板显式重新排列元素周围的空白(不剥离),并且在保留属性方面没有任何效果。你似乎打算将它作为一个身份变换,但传统的身份变换是这样的:

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

特别注意node()测试匹配元素和文本节点(以及注释和处理指令),但不匹配属性,并且如果您不想重新排列元素的文本节点相对对于它的子元素,那么你必须通过相同的xsl:apply-templates指令将它们全部转换。

此外,请注意,在许多XML应用程序中,仅用空白的文本分隔标记运行是无关紧要的。我没有理由认为您的特定应用程序属于例外情况,所以您真的应该问自己是否重要?#34;

假设它确实重要 - 例如因为你想要提高人类的可读性,即使XML主要是由不关心缩进的计算机程序使用 - 你应该考虑让你的XSL处理器为你提供缩进。为此,首先从输入文档中剥离所有无关紧要的空格开始:

<xsl:strip-space elements="*"/>

并通过要求处理器为您提供分层缩进来跟进:

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

这两个指令都具有全局效果,它们需要显示为xsl:stylesheetxsl:transform元素的直接子元素。这是已清理和更新的版本:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="/items/kitchen/furnitures/chairs">
    <xsl:choose>
      <xsl:when test="chair_1">
        <xsl:copy>
          <!-- also simplified the 'select' expression below: -->
          <xsl:apply-templates select="node()[not(self::chair_1)]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="chair_1"/>
      </xsl:when>
      <xsl:otherwise>
        BUNCH of code there if we don't have chair_1
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>