xml - 如何在 xsl:comment 中包含 xml 并保持缩进
问题描述
我正在编写一些 xsl 来将 xml 中的书籍大纲转换为一堆单独的 xml 文件(每章一个,加上一些前题等)。我将使用 来执行此操作<exsl:document>
,并且单个文件的大部分内容将写入 xsl 中。
我使用 xsltproc,所以 xslt 1.0。
我想要可以使用的文本注释,还想要<xsl:comment>
一些“注释掉”的 xml。正如这个问题中提到的,这是不可能使用的<xsl:comment>
。
该问题的答案用于<xsl:text disable-output-escaping="yes"><!--</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"><!--</xsl:text>
<child><name>commented child</name></child>
<xsl:text disable-output-escaping="yes">--></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 代码放在注释中?
解决方案
这是一个可用于注释掉任何 XML 节点或片段的转换:
- 不使用DOE
- 保留缩进
- 甚至尝试表达嵌套的评论——在评论遇到评论时不会忽略评论或抛出错误:
==============================
<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="'<!--
'"/>
<xsl:apply-templates select="*" mode="escapeToText"/>
<xsl:value-of select="'
-->'"/>
</xsl:template>
<xsl:template match="*" mode="escapeToText">
<xsl:value-of select="concat('<', name())"/>
<xsl:apply-templates select="@*" mode="escapeToText"/>
<xsl:value-of select="'>'"/>
<xsl:apply-templates select="node()" mode="escapeToText"/>
<xsl:value-of select="concat('</', name(), '>')"/>
</xsl:template>
<xsl:template match="@*" mode="escapeToText">
<xsl:value-of select="concat(' ', name(), '="')"/>
<xsl:call-template name="escapeDoubleDash">
<xsl:with-param name="pText" select="string(.)"/>
</xsl:call-template>
<xsl:value-of select="'"'"/>
</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('<?', name(), ' ', ., ' ?>')"/>
</xsl:template>
<xsl:template match="comment()">
<xsl:value-of select="concat('<!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 部分——然后你会看到文本未转义。这在一个例子中得到了最好的体现:
更新后的转换与上面提供的几乎相同,但是:
- 指令
method="text"
中没有<xsl:output>
- 注释文本是
<MyComment>
元素的文本节点 - 所有“注释 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="'<!--
'"/>
<xsl:apply-templates select="*" mode="escapeToText"/>
<xsl:value-of select="'
-->'"/>
</MyComment>
</xsl:template>
<xsl:template match="*" mode="escapeToText">
<xsl:value-of select="concat('<', name())"/>
<xsl:apply-templates select="@*" mode="escapeToText"/>
<xsl:value-of select="'>'"/>
<xsl:apply-templates select="node()" mode="escapeToText"/>
<xsl:value-of select="concat('</', name(), '>')"/>
</xsl:template>
<xsl:template match="@*" mode="escapeToText">
<xsl:value-of select="concat(' ', name(), '="')"/>
<xsl:call-template name="escapeDoubleDash">
<xsl:with-param name="pText" select="string(.)"/>
</xsl:call-template>
<xsl:value-of select="'"'"/>
</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('<?', name(), ' ', ., ' ?>')"/>
</xsl:template>
<xsl:template match="comment()">
<xsl:value-of select="concat('<!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 注释 ( <!-- -->
) 和处理“嵌套注释”的代码——这不再需要。
推荐阅读
- java - java SSLSocketFactory如何从密钥库中选择SSL期间的服务器证书和私钥
- ios - Api Gateway 和 Lambda 函数:响应正文
- python - AttributeError:类型对象'Cliente'没有属性'query'
- hibernate - oneToMany 关联中多个实体映射的性能问题
- sql - 优化使用多个子选择来显示列的 SQL 查询
- swagger - API-platform POST操作招摇页面为空
- xcode - 如何在 MacOS 上切换命令行工具
- ruby-on-rails - 如何实现模型之间的多重关联?
- postgresql - 使用 CASE WHEN 选择两列
- node.js - nuxt start 需要 node_modules 存在才能运行