Вот преобразование, которое можно использовать для закомментирования любого узла или фрагмента 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>
-->
Обновление :
В случае, если вы хотите, чтобы закомментированный результат появился как часть oДля XML-документа, то есть не иметь <xsl:output method="text"/>
, я предлагаю добавить специальный элемент, скажем, <MyComment>
, и получить результат комментирования как дочерний текстовый узел <MyComment>
.Как правило, закомментированный фрагмент XML будет отображаться с экранированными специальными символами.
Но есть одна хитрость - используйте раздел CDATA - тогда вы увидите текст без экранирования.Это лучше всего видно в примере:
Обновленное преобразование практически идентично приведенному выше, но:
- В директиве
<xsl:output>
нет method="text"
1054 * - Закомментированный текст является текстовым узлом
<MyComment>
элемента - Весь «закомментированный XML» - фактически представлен в виде текста, появляется в разделе CDATA и имеет значение unescaped
Вот измененное преобразование :
<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-комментариев (<!-- -->
) и кода, который обрабатывает «вложенные комментарии»- это больше не нужно.