XSLT:如何保留元素之间的空白?
XSLT: How to preserve whitespace between elements?
我有一个新要求,要使转换后的 XML 更具可读性,即在元素之间保留 cr、制表符和其他白色 space。
我似乎不知道如何保存白色space。
有人可以帮忙吗?
XML 文件
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
</Fragment>
</Wix>
XSL 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://schemas.microsoft.com/wix/2006/wi">
<xsl:preserve-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/m:Wix">
<xsl:message>Matched Wix</xsl:message>
<xsl:copy>
<!-- Insert the new include processing instruction -->
<xsl:processing-instruction name="include">
<xsl:text>$(sys.CURRENTDIR)src/includes/globals.wxi </xsl:text>
</xsl:processing-instruction>
<!-- place the existing children into the output -->
<xsl:apply-templates select="@* | *"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当前输出:
<?xml version="1.0" encoding="UTF-8"?><Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"><?include $(sys.CURRENTDIR)src/includes\globals.wxi ?><Fragment>
</Fragment></Wix>
期望输出:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)src/includes\globals.wxi ?>
<Fragment>
</Fragment>
</Wix>
考虑使用换行符 

和制表符实体 	
,方法是在流程指令前后添加以下文本。并确保将缩进输出 header 添加到顶部:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://schemas.microsoft.com/wix/2006/wi">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:preserve-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/m:Wix">
<xsl:message>Matched Wix</xsl:message>
<xsl:copy>
<xsl:text>
 	</xsl:text>
<!-- Insert the new include processing instruction -->
<xsl:processing-instruction name="include">
<xsl:text>$(sys.CURRENTDIR)src/includes/globals.wxi </xsl:text>
</xsl:processing-instruction>
<xsl:text>
 	</xsl:text>
<!-- place the existing children into the output -->
<xsl:apply-templates select="@* | *"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者,使用多个 non-break space 实体  
代替制表符以实现更精确的对齐:
<xsl:text>
    </xsl:text>
输出
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)src/includes/globals.wxi?>
<Fragment>
</Fragment>
</Wix>
我选择的漂亮打印工具是 xmlint。
xmllint --format old.xml > new.xml
但我确实看到您正在添加处理指令。所以需要xslt。
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://schemas.microsoft.com/wix/2006/wi"
exclude-result-prefixes="m">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:preserve-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="m:Wix">
<xsl:message>Matched Wix</xsl:message>
<Wix>
<xsl:call-template name="CR"/>
<xsl:call-template name="TAB"/>
<!-- Insert the new include processing instruction -->
<xsl:processing-instruction name="include">
<xsl:text>$(sys.CURRENTDIR)src/includes/globals.wxi</xsl:text>
</xsl:processing-instruction>
<!-- place the existing children into the output -->
<xsl:apply-templates/>
</Wix>
</xsl:template>
<xsl:template match="m:Fragment">
<Fragment>
<xsl:apply-templates/>
</Fragment>
</xsl:template>
<xsl:template name="CR">
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="TAB">
<xsl:text>	</xsl:text>
</xsl:template>
</xsl:stylesheet>
如果您的真实 XML 变得更复杂,您可能需要先进行 xmllint。然后做一个简单的xslt添加处理指令。 Xmllint 是漂亮的空白感知,xslt 你必须把它烤进去。
您的输入中有三个空白文本节点:两个是 Fragment 元素的同级元素,一个是 Fragment 元素的子元素。
前两个不会复制到您的输出中,因为您的 m:Wix 元素模板会忽略它们:它 <xsl:apply-templates select="@* | *"/>
只选择元素子元素,而不选择文本节点子元素。
Fragment 的空白文本内容已处理,并保留在您的输出中。
现在:你在问题中说了两件事:(a) 你想让输出可读,(b) 你想保留输入中的空白。我建议 (b) 不是实现 (a) 的最佳方式。实现 (a) 的最佳方法是忽略输入中存在的空格,并使用 xsl:output indent="yes"
在输出中添加新的空格。
但是,如果您确实想将空格从输入复制到输出,则在处理元素的子元素时需要使用 select="node()"
而不是 select="*"
。
我有一个新要求,要使转换后的 XML 更具可读性,即在元素之间保留 cr、制表符和其他白色 space。
我似乎不知道如何保存白色space。
有人可以帮忙吗?
XML 文件
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
</Fragment>
</Wix>
XSL 文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://schemas.microsoft.com/wix/2006/wi">
<xsl:preserve-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/m:Wix">
<xsl:message>Matched Wix</xsl:message>
<xsl:copy>
<!-- Insert the new include processing instruction -->
<xsl:processing-instruction name="include">
<xsl:text>$(sys.CURRENTDIR)src/includes/globals.wxi </xsl:text>
</xsl:processing-instruction>
<!-- place the existing children into the output -->
<xsl:apply-templates select="@* | *"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当前输出:
<?xml version="1.0" encoding="UTF-8"?><Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"><?include $(sys.CURRENTDIR)src/includes\globals.wxi ?><Fragment>
</Fragment></Wix>
期望输出:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)src/includes\globals.wxi ?>
<Fragment>
</Fragment>
</Wix>
考虑使用换行符 

和制表符实体 	
,方法是在流程指令前后添加以下文本。并确保将缩进输出 header 添加到顶部:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://schemas.microsoft.com/wix/2006/wi">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:preserve-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/m:Wix">
<xsl:message>Matched Wix</xsl:message>
<xsl:copy>
<xsl:text>
 	</xsl:text>
<!-- Insert the new include processing instruction -->
<xsl:processing-instruction name="include">
<xsl:text>$(sys.CURRENTDIR)src/includes/globals.wxi </xsl:text>
</xsl:processing-instruction>
<xsl:text>
 	</xsl:text>
<!-- place the existing children into the output -->
<xsl:apply-templates select="@* | *"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者,使用多个 non-break space 实体  
代替制表符以实现更精确的对齐:
<xsl:text>
    </xsl:text>
输出
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)src/includes/globals.wxi?>
<Fragment>
</Fragment>
</Wix>
我选择的漂亮打印工具是 xmlint。
xmllint --format old.xml > new.xml
但我确实看到您正在添加处理指令。所以需要xslt。
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://schemas.microsoft.com/wix/2006/wi"
exclude-result-prefixes="m">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:preserve-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="m:Wix">
<xsl:message>Matched Wix</xsl:message>
<Wix>
<xsl:call-template name="CR"/>
<xsl:call-template name="TAB"/>
<!-- Insert the new include processing instruction -->
<xsl:processing-instruction name="include">
<xsl:text>$(sys.CURRENTDIR)src/includes/globals.wxi</xsl:text>
</xsl:processing-instruction>
<!-- place the existing children into the output -->
<xsl:apply-templates/>
</Wix>
</xsl:template>
<xsl:template match="m:Fragment">
<Fragment>
<xsl:apply-templates/>
</Fragment>
</xsl:template>
<xsl:template name="CR">
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="TAB">
<xsl:text>	</xsl:text>
</xsl:template>
</xsl:stylesheet>
如果您的真实 XML 变得更复杂,您可能需要先进行 xmllint。然后做一个简单的xslt添加处理指令。 Xmllint 是漂亮的空白感知,xslt 你必须把它烤进去。
您的输入中有三个空白文本节点:两个是 Fragment 元素的同级元素,一个是 Fragment 元素的子元素。
前两个不会复制到您的输出中,因为您的 m:Wix 元素模板会忽略它们:它 <xsl:apply-templates select="@* | *"/>
只选择元素子元素,而不选择文本节点子元素。
Fragment 的空白文本内容已处理,并保留在您的输出中。
现在:你在问题中说了两件事:(a) 你想让输出可读,(b) 你想保留输入中的空白。我建议 (b) 不是实现 (a) 的最佳方式。实现 (a) 的最佳方法是忽略输入中存在的空格,并使用 xsl:output indent="yes"
在输出中添加新的空格。
但是,如果您确实想将空格从输入复制到输出,则在处理元素的子元素时需要使用 select="node()"
而不是 select="*"
。