转换前更新 XSL 文件

Posted

技术标签:

【中文标题】转换前更新 XSL 文件【英文标题】:Update XSL file before transform 【发布时间】:2021-09-15 03:50:30 【问题描述】:

TNT 以 XML 和 XSL 文件的形式提供清单数据以将该数据转换成。

然后输出是用于打印的清单的 html 文件。

这是 XSL 文件:

https://express.tnt.com/expresswebservices-website/stylesheets/HTMLManifestRenderer.xsl

在xsl文件中有以下内容:

<xsl:apply-templates select="PACKAGE[position() >= 1 and position() < 4]" mode="int"/>

根据我在这方面极其有限的知识,这似乎阻止了清单中显示超过 3 个项目。

我想取消这个限制。就像把“

我有以下有效的代码:

public static string TransformXmlStringWithXslString(string xmlString, string XSLStylesheetUrl)

    AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);

    // process our xml
    XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(xmlString));
    XPathDocument xPathDocument = new XPathDocument(xmlTextReader);

    XsltSettings settings = new XsltSettings(true, true);

    // process the xsl
    XmlTextReader xmlTextReaderXslt = new XmlTextReader(XSLStylesheetUrl);
    XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
    xslCompiledTransform.Load(xmlTextReaderXslt, settings, new XmlUrlResolver());

    // handle the output stream
    StringBuilder stringBuilder = new StringBuilder();
    TextWriter textWriter = new StringWriter(stringBuilder);

    // do the transform
    xslCompiledTransform.Transform(xPathDocument, null, textWriter);
    return stringBuilder.ToString();

在将 XML 推送到其中之前更新该值的最佳方法是什么?

【问题讨论】:

不要改变!!!模式旨在使客户端和服务器兼容。如果您更改架构,您可能无法将数据传输到另一个应用程序。 @jdweng 但在这种情况下,它只是呈现用于打印的清单文件的 HTML... 是否每超过 3 个项目提供一次数据?如果架构的最大值为 3,我认为您不会每个人都获得超过 3 个项目。 是的。有时会发送超过 3 个包裹。我们不理解他们施加此限制的“商业”原因。但是为了我们使用文档,我们需要更多 【参考方案1】:

与其修改样式表,不如考虑编写一个覆盖样式表来导入提供的样式表并替换相关的模板规则:

<xsl:stylesheet ...>
<xsl:import href="existingStylesheet.xsl"/>
<xsl:param name="maxPackages" select="5"/>

<xsl:template match="CONSIGNMENT" mode="IntPacks">
<div class="row packages">
<div class="packagescolumn1">
<div class="Line100">
<font class="newheader"> Description (incl. packing and marks) </font>
</div>
</div>
<div class="packagescolumn2">
<div class="Line100">
<font class="newheader"> Dimensions (L x W x H) </font>
</div>
</div>
<div class="packagescolumn3">
<div class="Line100">
<font class="newheader"> Total Consignment Volume   </font>
<font class="newdata">
<xsl:value-of select="concat(format-number(TOTALVOLUME, '##0.000'), ' ', PACKAGE/VOLUME/@units)"/>
</font>
</div>
</div>
<xsl:apply-templates select="PACKAGE[position() >= 1 and position() &lt;= $maxPackages]" mode="int"/>
</div>
</xsl:template>

</xsl:stylesheet>

【讨论】:

我已将您的文件上传到 sherprinsurance.blob.core.windows.net/xslhost/Manifest.xsl,将 href 更改为原始文件,但它在我的浏览器中呈现错误。你能帮忙吗? @trevor,用/&gt;关闭空的xsl:import @rene,解决方案的哪一部分需要解释?是 xsl:import 在导入的样式表中覆盖声明的一般原则吗? @MichaelKay 是的,导入覆盖现有声明令我感到惊讶。我一直认为它是命中或未命中和/或特定于实现的行为,而不是特定的行为。 @rene:绝对不是,规范中对导入优先级进行了非常仔细的解释,这是该语言的一个非常重要的特性,可能还不够广泛理解。当然,在 XSLT 的原始用例中尤其重要,即定义相同 XML 的替代呈现方式,其中一个样式表可以对另一个样式表进行小的修改。【参考方案2】:

最简单的方法是将XSL stylesheet(不要将其与 XML Schema 混淆!)加载到 XDocument 中,然后找到要更改的元素。此代码找到您所追求的特定元素并进行更改:

var xslNS = (XNamespace) "http://www.w3.org/1999/XSL/Transform";
    
var xdoc = XDocument.Load(@"https://express.tnt.com/expresswebservices-website/stylesheets/HTMLManifestRenderer.xsl");
var xelement = xdoc
    .Descendants(xslNS + "apply-templates")
    .Where(e => (string) e.Attribute("select") == "PACKAGE[position() >= 1 and position() < 4]" 
       && (string) e.Attribute("mode") == "int");
var apply = xelement.First();
apply.SetAttributeValue("select", "PACKAGE[position() >= 1 and position() < 9999]");    

然后,您可以在 XDocument 实例上使用 CreateReader 方法来获取需要获取已编译 XSL 的阅读器。将其合并到您的代码中,它看起来像这样:

public static string TransformXmlStringWithXslString(string xmlString, string XSLStylesheetUrl)

     AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);

     // process our xml
     XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(xmlString));
     XPathDocument xPathDocument = new XPathDocument(xmlTextReader);

     XsltSettings settings = new XsltSettings(true, true);

     // process the xsl
     var xslNS = (XNamespace) "http://www.w3.org/1999/XSL/Transform";
     
     var xdoc = XDocument.Load(XSLStylesheetUrl);
     var xelement = xdoc
         .Descendants(xslNS +"apply-templates")
         .Where(e => (string) e.Attribute("select") == "PACKAGE[position() >= 1 and position() < 4]" 
            && (string) e.Attribute("mode") == "int");
     var apply = xelement.First();
     apply.SetAttributeValue("select", "PACKAGE[position() >= 1 and position() < 9999]");
     
     XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
     xslCompiledTransform.Load(xdoc.CreateReader(), settings, new XmlUrlResolver());

     // handle the output stream
     StringBuilder stringBuilder = new StringBuilder();
     TextWriter textWriter = new StringWriter(stringBuilder);

     // do the transform
     xslCompiledTransform.Transform(xPathDocument, null, textWriter);
     return stringBuilder.ToString();

【讨论】:

以上是关于转换前更新 XSL 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何将xsl文件转换为sef文件

如何解决从字符串加载 XSL 的转换中包含的 XSL?

可以让 Chrome 对本地文件执行 XSL 转换吗?

转换 XSL

使用 XSL 转换合并两个 XML 文件

使用 Saxon 对 Msi 文件 (xml) 运行 XSL 转换