gpt4 book ai didi

c# - 使用 XslCompiledTransform 去除空白

转载 作者:太空狗 更新时间:2023-10-29 18:36:03 25 4
gpt4 key购买 nike

我正在尝试将大型应用程序从 XslTransform 迁移到已编译的 xsl 文件和 XslCompiledTransform

应用程序使用 Xsl 创建 HTML 文件,转换数据 (Xml) 通过 传递给 Xsl >XmlDataDocument,从数据库返回。

我已经改变了所有这些,所以现在我(至少暂时):

C#

 public string ProcessCompiledXsl(XmlDataDocument xml)
{
StringBuilder stringControl = new StringBuilder();
XslCompiledTransform xslTran = new XslCompiledTransform();

xslTran.Load(
System.Reflection.Assembly.Load("CompiledXsl").GetType(dllName)
);

xslTran.Transform(xml, this.Arguments, XmlWriter.Create(stringControl, othersettings), null);

return stringControl.ToString();
}

XSL(只是一个例子)

...
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>

问题

这行得通,但 xsl 正在去除标签输出之间的空白:

<a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a><a...etc

我试过:

  • 使用 xml:space="preserve" 但我无法让它工作
  • 覆盖OutputSettings,但我没有得到任何好的结果(也许我错过了什么)
  • 使用 xsl:output method="xml",这可行,但会创建自闭标签和许多其他问题

所以我不知道该怎么办。也许我做的不对。非常感谢任何帮助。

谢谢!

编辑

仅供将来引用,如果您想解决这个问题而保留每个 XSL,可以尝试 this C# class我写的,命名为CustomHtmlWriter

基本上我所做的是从 XmlTextWriter 扩展并修改编写每个标记的 startend 的方法。

在这种特殊情况下,您可以像这样使用它:

    StringBuilder sb = new StringBuilder();
CustomHtmlWriter writer = new CustomHtmlWriter(sb);

xslTran.Transform(nodeReader, this.Arguments, writer);

return sb.ToString();

希望对大家有帮助。

最佳答案

我。方案一:

这里先分析一下问题:

鉴于此源 XML 文档(发明的,因为您没有提供任何文档):

<Object>
<Table>

</Table>

<Table>

</Table>

<Table>

</Table>

<Table>

</Table>
</Object>

这个转换:

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

<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
<!--
<xsl:template match="Table">
<a href="#">
Table here
</a>
</xsl:template>
-->
</xsl:stylesheet>

完全重现了问题 -- 结果是:

<a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a>

现在,只需取消注释模板的注释并注释掉第一个模板:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<!--
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
-->
<xsl:template match="Table">
<a href="#">
Table here
</a>
</xsl:template>
</xsl:stylesheet>

结果有想要的缩进:

 <a href="#">
Table here
</a>

<a href="#">
Table here
</a>

<a href="#">
Table here
</a>

<a href="#">
Table here
</a>

这是解决方案 1


二。方案二:

此解决方案可以将对现有 XSLT 代码的必要修改减少到最少:

这是一个两次转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
<xsl:output method="html"/>

<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:variable>

<xsl:apply-templates select=
"ext:node-set($vrtfPass1)" mode="pass2"/>
</xsl:template>

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

<xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
<xsl:text>&#xA;</xsl:text>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

我们的想法是,我们甚至不触及现有代码,而是捕获其输出并仅使用几行附加代码,我们将输出格式化为具有所需的最终外观。

当此转换应用于同一个 XML 文档时,会产生相同的、想要的结果:

<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>

最后,这里演示了如何在不触及任何现有 XSLT 代码的情况下引入这个小改动:

让我们在 c:\temp\delete\existing.xsl 中有这个现有代码:

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

<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

如果我们运行它,我们会得到有问题的输出

现在,我们运行此转换,而不是运行 existing.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
<xsl:import href="file:///c:/temp/delete/existing.xsl"/>
<xsl:output method="html"/>


<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-imports/>
</xsl:variable>

<xsl:apply-templates select=
"ext:node-set($vrtfPass1)" mode="pass2"/>
</xsl:template>

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

<xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
<xsl:text>&#xA;</xsl:text>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

结果是想要的结果,现有代码根本没有动过:

<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>

解释:

  1. 我们使用 xsl:import 导入位于导入优先层次结构顶层的任何现有代码(未被其他样式表导入) .

  2. 我们将现有转换的输出捕获到一个变量中。它具有臭名昭著的 RTF ( Result Tree Fragment ),需要将其转换为常规树以便进一步处理。

  3. 关键时刻在表演 xsl:apply-imports 在捕获转换的输出时。这确保现有代码中的任何模板(即使是我们覆盖的模板——例如匹配 / 的模板)都将被选择执行,就像现有转换由其自身执行时的情况一样)。

  4. 我们使用 msxsl:node-set() 将 RTF 转换为常规树 扩展函数(XslCompiledTransform 还支持 EXSLT node-set() 扩展函数)。

  5. 我们对如此生成的常规树进行修饰调整。

请注意:

这表示在不触及现有代码的情况下对现有转换进行后处理的通用算法

关于c# - 使用 XslCompiledTransform 去除空白,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12218604/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com