如何在xsl:comment中包含xml并保持缩进

时间:2019-06-05 16:30:21

标签: xml xslt xslt-1.0

我正在编写一些xsl,以将xml中的书籍大纲转换为一堆单独的xml文件(每个章节一个,外加一些前置内容,等等)。我将使用<exsl:document>进行此操作,各个文件的大部分内容都将写入xsl内。

我使用xsltproc,所以使用xslt 1.0。

我想要文本注释,我可以使用<xsl:comment>获得注释,但也需要一些“注释掉”的xml。如this question中所述,无法使用<xsl:comment>

该问题的answer使用<xsl:text disable-output-escaping="yes">&lt;!--</xsl:text>来包装注释的xml。这是可行的,除了添加后,输出不再正确缩进即可。

例如,以下xsl:

<?xml version='1.0' encoding="UTF-8"?>

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

<xsl:template match="/">
<root>
  <xsl:comment>Text comment</xsl:comment>
  <child><name>A child</name></child>
  <xsl:text disable-output-escaping="yes">&lt;!--</xsl:text>
  <child><name>commented child</name></child>
  <xsl:text disable-output-escaping="yes">--&gt;</xsl:text>
</root>
</xsl:template>

</xsl:stylesheet>

提供注释中的xml,但没有缩进:

<root><!--Text comment--><child><name>A child</name></child><!--<child><name>commented child</name></child>--></root>

在使用时:

<xsl:template match="/">
<root>
  <xsl:comment>Text comment</xsl:comment>
  <child><name>A child</name></child>
  <xsl:comment><child><name>commented child</name></child></xsl:comment>
</root>
</xsl:template>

缩进很好,但注释中没有xml标记:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <!--Text comment-->
  <child>
    <name>A child</name>
  </child>
  <!--commented child-->
</root>

有什么办法可以缩进,但可以将xml代码放在注释中吗?

1 个答案:

答案 0 :(得分:0)

这是可用于注释掉任何XML节点或片段的转换,

  1. 不使用DOE
  2. 保留缩进
  3. 即使试图表达嵌套的注释,也不会忽略注释,也不会在遇到要注释的注释时引发错误:

============================

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text" indent="yes"/>

  <xsl:template match="/">
    <xsl:value-of select="'&lt;!--&#xA;'"/>
      <xsl:apply-templates select="*" mode="escapeToText"/>
    <xsl:value-of select="'&#xA;-->'"/>
  </xsl:template>


  <xsl:template match="*" mode="escapeToText">
    <xsl:value-of select="concat('&lt;', name())"/>

    <xsl:apply-templates select="@*" mode="escapeToText"/>
    <xsl:value-of select="'>'"/>

    <xsl:apply-templates select="node()" mode="escapeToText"/>
    <xsl:value-of select="concat('&lt;/', name(), '>')"/>
  </xsl:template>

  <xsl:template match="@*" mode="escapeToText">
    <xsl:value-of select="concat(' ', name(), '=&quot;')"/>
    <xsl:call-template name="escapeDoubleDash">
      <xsl:with-param name="pText" select="string(.)"/>
    </xsl:call-template>
    <xsl:value-of select="'&quot;'"/>
  </xsl:template>

  <xsl:template match="text()" mode="escapeToText">
    <xsl:call-template name="escapeDoubleDash">
      <xsl:with-param name="pText" select="."/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="processing-instruction()" mode="escapeToText">
    <xsl:value-of select="concat('&lt;?', name(), ' ', ., ' ?>')"/>
  </xsl:template>

  <xsl:template match="comment()">
    <xsl:value-of select="concat('&lt;!CM ', ., 'CM>')"/>
  </xsl:template>

  <xsl:template name="escapeDoubleDash">
   <xsl:param name="pText"/>

   <xsl:choose>
     <xsl:when test="contains($pText, '--')">
       <xsl:value-of select="substring-before($pText, '--')"/>
       <xsl:value-of select="'!-!-'"/>
       <xsl:call-template name="escapeDoubleDash">
         <xsl:with-param name="pText" select="substring-after($pText, '--')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise><xsl:value-of select="$pText"/></xsl:otherwise>
   </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

当此转换应用于任何源xml文档时,例如:

<input>
    <name>Jack</name>
    <age>23</age>
    <type-10-num>1</type-10-num>
    <type-20-num>2</type-20-num>
    <type-20-char>3</type-20-char>
    <type-180-num>4</type-180-num>
    <type-180-char>5</type-180-char>
    <type-180-str>6</type-180-str>
</input>

产生所需的缩进结果

<!--
<input>
    <name>Jack</name>
    <age>23</age>
    <type-10-num>1</type-10-num>
    <type-20-num>2</type-20-num>
    <type-20-char>3</type-20-char>
    <type-180-num>4</type-180-num>
    <type-180-char>5</type-180-char>
    <type-180-str>6</type-180-str>
</input>
-->

以下是注释掉的非常复杂的XML文档的样子-让我们将此转换应用于...本身。

为完整起见,我在模板匹配属性之前添加了注释和处理说明:

  <?somePI x="y" z="t" pqr ?>

  <!-- A Comment node -->

结果如预期:

<!--
<xsl:stylesheet version="1.0">
 <xsl:output method="text" indent="yes"></xsl:output>

  <xsl:template match="/">
    <xsl:value-of select="'<!!-!-
'"></xsl:value-of>
      <xsl:apply-templates select="*" mode="escapeToText"></xsl:apply-templates>
    <xsl:value-of select="'
!-!->'"></xsl:value-of>
  </xsl:template>


  <xsl:template match="*" mode="escapeToText">
    <xsl:value-of select="concat('<', name())"></xsl:value-of>

    <xsl:apply-templates select="@*" mode="escapeToText"></xsl:apply-templates>
    <xsl:value-of select="'>'"></xsl:value-of>

    <xsl:apply-templates select="node()" mode="escapeToText"></xsl:apply-templates>
    <xsl:value-of select="concat('</', name(), '>')"></xsl:value-of>
  </xsl:template>

  <?somePI x="y" z="t" pqr  ?>

  <!CM  A Comment node CM>
  <xsl:template match="@*" mode="escapeToText">
    <xsl:value-of select="concat(' ', name(), '="')"></xsl:value-of>
    <xsl:call-template name="escapeDoubleDash">
      <xsl:with-param name="pText" select="string(.)"></xsl:with-param>
    </xsl:call-template>
    <xsl:value-of select="'"'"></xsl:value-of>
  </xsl:template>

  <xsl:template match="text()" mode="escapeToText">
    <xsl:call-template name="escapeDoubleDash">
      <xsl:with-param name="pText" select="."></xsl:with-param>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="processing-instruction()" mode="escapeToText">
    <xsl:value-of select="concat('<?', name(), ' ', ., ' ?>')"></xsl:value-of>
  </xsl:template>

  <xsl:template match="comment()">
    <xsl:value-of select="concat('<!CM ', ., 'CM>')"></xsl:value-of>
  </xsl:template>

  <xsl:template name="escapeDoubleDash">
   <xsl:param name="pText"></xsl:param>

   <xsl:choose>
     <xsl:when test="contains($pText, '!-!-')">
       <xsl:value-of select="substring-before($pText, '!-!-')"></xsl:value-of>
       <xsl:value-of select="'!-!-'"></xsl:value-of>
       <xsl:call-template name="escapeDoubleDash">
         <xsl:with-param name="pText" select="substring-after($pText, '!-!-')"></xsl:with-param>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise><xsl:value-of select="$pText"></xsl:value-of></xsl:otherwise>
   </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
-->

更新

如果您希望注释的结果作为XML文档的一部分出现-也就是说,不要包含<xsl:output method="text"/>,  我建议添加一个特殊元素,例如<MyComment>并将注释的结果作为<MyComment>的文本节点子代生成。通常,带有注释的xml片段会以特殊字符转义。

但是有一个窍门-使用CDATA部分-然后您将看到文本未转义。最好在一个示例中看到:

更新后的转换与上面提供的转换几乎相同,但是:

  1. method="text"指令中没有<xsl:output>
  2. 评论的文本是<MyComment>元素的文本节点
  3. 所有“注释的XML”(实际上表示为文本)出现在CDATA部分中,并且未转义

这是修改后的转换

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output indent="yes" cdata-section-elements="MyComment"/>

  <xsl:template match="/">
   <MyComment>
     <xsl:value-of select="'&lt;!--&#xA;'"/>
       <xsl:apply-templates select="*" mode="escapeToText"/>
     <xsl:value-of select="'&#xA;-->'"/>
    </MyComment>
  </xsl:template>


  <xsl:template match="*" mode="escapeToText">
    <xsl:value-of select="concat('&lt;', name())"/>

    <xsl:apply-templates select="@*" mode="escapeToText"/>
    <xsl:value-of select="'>'"/>

    <xsl:apply-templates select="node()" mode="escapeToText"/>
    <xsl:value-of select="concat('&lt;/', name(), '>')"/>
  </xsl:template>

  <xsl:template match="@*" mode="escapeToText">
    <xsl:value-of select="concat(' ', name(), '=&quot;')"/>
    <xsl:call-template name="escapeDoubleDash">
      <xsl:with-param name="pText" select="string(.)"/>
    </xsl:call-template>
    <xsl:value-of select="'&quot;'"/>
  </xsl:template>

  <xsl:template match="text()" mode="escapeToText">
    <xsl:call-template name="escapeDoubleDash">
      <xsl:with-param name="pText" select="."/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="processing-instruction()" mode="escapeToText">
    <xsl:value-of select="concat('&lt;?', name(), ' ', ., ' ?>')"/>
  </xsl:template>

  <xsl:template match="comment()">
    <xsl:value-of select="concat('&lt;!CM ', ., 'CM>')"/>
  </xsl:template>

  <xsl:template name="escapeDoubleDash">
   <xsl:param name="pText"/>

   <xsl:choose>
     <xsl:when test="contains($pText, '--')">
       <xsl:value-of select="substring-before($pText, '--')"/>
       <xsl:value-of select="'!-!-'"/>
       <xsl:call-template name="escapeDoubleDash">
         <xsl:with-param name="pText" select="substring-after($pText, '--')"/>
       </xsl:call-template>
     </xsl:when>
     <xsl:otherwise><xsl:value-of select="$pText"/></xsl:otherwise>
   </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

当我们将此转换应用于以下XML文档时:

<input>
    <name>Jack</name>
    <age>23</age>
    <type-10-num>1</type-10-num>
    <type-20-num>2</type-20-num>
    <type-20-char>3</type-20-char>
    <type-180-num>4</type-180-num>
    <type-180-char>5</type-180-char>
    <type-180-str>6</type-180-str>
</input>

产生了想要的,未经转义的评论:

<MyComment><![CDATA[<!--
<input>
    <name>Jack</name>
    <age>23</age>
    <type-10-num>1</type-10-num>
    <type-20-num>2</type-20-num>
    <type-20-char>3</type-20-char>
    <type-180-num>4</type-180-num>
    <type-180-char>5</type-180-char>
    <type-180-str>6</type-180-str>
</input>
-->]]></MyComment>

我们可以摆脱XML注释(<!-- -->)和处理“嵌套注释”的代码-不再需要。

相关问题