编写有效的 XSLT

Posted

技术标签:

【中文标题】编写有效的 XSLT【英文标题】:Writing effective XSLT 【发布时间】:2009-04-12 00:24:52 【问题描述】:

的原则和模式是什么?

当我说“有效”时,我的意思是它是

    结构良好且可读性强 简单、简洁 高效(即具有良好的性能)

简而言之,我正在寻找 XSLT 的最佳实践。

我已经看过the question regarding efficiency,但是如果你无法理解它在做什么,那么高效的代码就会失去它的价值。

【问题讨论】:

【参考方案1】:

我。优雅的 XSLT 代码

人们经常可以找到漂亮的 XSLT 代码示例,尤其是当 XSLT 用作函数式编程语言时

有关示例,请参阅 FXSL 2.0 上的 this article — XSLT 2.0 的函数式编程库。

作为一种 FP 语言,XSLT 也是一个declarative language。除其他外,这意味着一个人声明,指定现有关系。

这样的定义通常不需要任何额外的代码来产生结果——它本身就是它自己的实现,或者一个可执行的定义或可执行的规范

这是一个小例子

此 XPath 2.0 表达式定义自然数的最大 Prime Factor”:

if(f:isPrime($pNum))
  then $pNum
  else
    for $vEnd in xs:integer(floor(f:sqrt($pNum, 0.1E0))),
        $vDiv1 in (2 to $vEnd)[$pNum mod . = 0][1],
        $vDiv2 in $pNum idiv $vDiv1
      return
        max((f:maxPrimeFactor($vDiv1),f:maxPrimeFactor($vDiv2)))

用英语发音,如果 pNum 是数字 pNum 的最大素数是数字本身素数,否则如果vDiv1vDiv2pNum的两个因数,则@的最大素数987654344@vDiv1vDiv2 的最大素因数中的较大者。

我们如何使用它来实际计算 XSLT 中的最大素因子? 我们只需将上面的定义包装起来<xsl:function> 中,然后......得到结果!

 <xsl:function name="f:maxPrimeFactor" as="xs:integer">
  <xsl:param name="pNum" as="xs:integer"/>

  <xsl:sequence select=
   "if(f:isPrime($pNum))
      then $pNum
      else
        for $vEnd in xs:integer(floor(f:sqrt($pNum, 0.1E0))),
            $vDiv1 in (2 to $vEnd)[$pNum mod . = 0][1],
            $vDiv2 in $pNum idiv $vDiv1
          return
            max((f:maxPrimeFactor($vDiv1),f:maxPrimeFactor($vDiv2)))
   "/>
 </xsl:function>

那么我们可以calculate the MPF for any natural number,例如:

f:maxPrimeFactor(600851475143) = 6857

至于效率,嗯,这个转换只需要 0.109 秒

其他优雅高效的 XSLT 代码示例

Tim BrayWide Finder,已解决 hereCascade deletions Transitive closure Finding all anagrams一个字 Concordance 文本语料库(旧约) Spelling checking(莎士比亚的奥赛罗) Sudoku solver

二。一些规则

以下是编写“优质 XSLT 代码”的一些规则,取自 Mukul Ghandi's blog

可以使用tool developed by Mukul检查/强制执行它们:

    DontUseDoubleSlashOperatorNearRoot:避免在大树的根部附近使用 // 运算符。

    DontUseDoubleSlashOperator:避免在 XPath 表达式中使用运算符 //。

    SettingValueOfVariableIncorrectly:如果分配字符串值,则使用“选择”语法将值分配给变量。

    EmptyContentInInstructions:不要将空内容用于“xsl:for-each”“xsl:if”“xsl:when”等指令。

    DontUseNodeSetExtension:如果使用 XSLT 2.0,请勿使用节点集扩展功能。

    RedundantNamespaceDeclarations:xsl:stylesheet 元素中有多余的命名空间声明。

    UnusedFunction:样式表函数未使用。

    UnusedNamedTemplate:样式表中的命名模板未使用。

    UnusedVariable:样式表中未使用变量。

    UnusedFunctionTemplateParameter:函数或模板参数在函数/模板主体中未使用。

    TooManySmallTemplates:样式表中的低粒度模板过多(10 个或更多)。

    MonolithicDesign:在样式表中使用单个模板/函数。您可以将代码模块化。

    OutputMethodXml:生成 html 代码时使用输出方法 'xml'。

    NotUsingSchemaTypes:在 XSLT 2.0 模式下工作时,样式表未使用任何内置模式类型(xs:string 等)。

    UsingNameOrLocalNameFunction:在 local-name() 可能合适时使用 name() 函数(反之亦然)。

    FunctionTemplateComplexity:函数或模板的大小/复杂度很高。需要重构代码。

    NullOutputFromStylesheet:样式表没有生成任何有用的输出。请重新查看样式表逻辑。

    UsingNamespaceAxis:在 XSLT 2.0 模式下工作时使用已弃用的命名空间轴。

    CanUseAbbreviatedAxisSpecifier:使用长轴说明符,例如 child::、attribute:: 或 parent::node()。

    UsingDisableOutputEscaping:已将禁用输出转义属性设置为“是”。请重新查看样式表逻辑。

    NotCreatingElementCorrectly:如果可以直接使用 xsl:element 指令创建元素节点。

    AreYouConfusingVariableAndNode:您可能将变量引用与节点引用混淆了。 (由 Alain Benedetti 供稿)

    IncorrectUseOfBooleanConstants:错误地将布尔常量用作“真”或“假”。 (由托尼·拉维尼奥供稿)

    ShortNames:对变量/函数/模板使用单字符名称。为这些功能使用有意义的名称。

    NameStartsWithNumeric:变量/函数/模板名称以数字字符开头

【讨论】:

【参考方案2】:

最佳实践 1尽可能使用模板代替 (这是 99% 的情况)

(我可以在最佳实践中添加可维护性作为额外成分吗,恕我直言,即使是最重要的成分)

要理解 xsl,您确实需要一些练习。 不明白什么。当然是非常相对的。

这对 XSLT 来说是双重的,因为 xsl:for-each 结构往往是

更具可读性

对于新手来说,其实是

结构较少, 不那么简单, 不够简洁和 可维护性差很多

比模板,而且只是

因此具有同等可读性(充其量!!)。具有最少的模板经验。

永远不要使用 元素!

我承认,标题有点 夸张,确实存在,我曾经 告诉,其中一个“xsl for each”的情况 可以有它的优点,但那些情况 非常非常罕见。

我曾经不得不想出一个相当 复杂的 xml/xslt 客户端站点 不到一周,并使用了 到处都是 for-each 元素。 现在,几年后,有点, 更明智的是,我花时间重写了 初始代码,仅使用模板。 现在的代码干净多了 适应性更强。

要么你知道这一点,要么你 应该:

【讨论】:

我倾向于认为可维护性是一种简单、简洁、结构良好且可读性强的产品。我错过了什么? 可维护性也取决于灵活性。 实际上,种情况必须使用 @Dimitre,当然!这就是我说的原因:我承认,标题有些夸张,有人告诉我,确实存在“xsl for each”可以有其优点的情况,但这种情况非常非常罕见。【参考方案3】:

我认为回答这个问题的一个好方法是从另一个方面来解决这个问题。哪些实践使 XSLT无效,为什么?

我看到的一些导致 XSLT 无效的情况:

    过度使用for-each每个人都这么说;我再说一遍。我发现for-each 通常是开发人员试图在声明性语言中采用传统编程技术的标志。

    未充分利用 XPath。 我看到的很多糟糕的 XSLT 的存在纯粹是因为开发人员不了解谓词、轴说明符、position()current() 等等他改为使用 XSLT 结构实现逻辑。

    未充分利用元数据。您有时可以通过为您的转换提供元数据来消除大量的 XSLT。

    未充分利用预处理。例如,如果 XML 文档包含必须使用 XSLT 字符串操作进行解析的数据,则在外部进行所有解析通常要简单得多XSLT 并将解析的结果添加到 XML 或将解析的结果作为参数传递给转换。我见过一些非常难以维护的 XSLT 实现业务逻辑,在 C# 或 Python 中实现这些逻辑是微不足道的。

我在自己的 XSLT 世界中遇到的最大问题(我正在维护几个 3,000 多行转换)是死代码。我确信我的转换中的某些模板将永远不会再次使用,因为它们正在测试的条件将永远不会再次出现。没有办法以编程方式确定像 &lt;xsl:template match="SomeField[contains(., "some value")]&gt; 这样的东西是活着还是死了,因为它取决于元数据无法告诉你的东西。

【讨论】:

您好 Robert,减少死代码的一种方法是使用函数/模板库,例如 FXSL。那么很可能,您永远不必编写超过 3000 行的转换。我写过的最复杂的样式表之一——XPath 2.0 的解析器只有 657 行。当然,许多 FXSL 功能。二手 我确实使用模板库。我遇到的问题是不同的。如果我停止在我的 XML 中使用“Foo”元素,没有任何东西告诉我从我的 XSLT 中删除它的匹配模板。【参考方案4】:

文件问题

1.很多小文件比几个大文件好。

将 hamburger.xsl 拆分为 i-bread.xsl 和 i-beef.xsl。

2。使用“i-”前缀包含/导入的文件。

它作为一个指示文件应该谨慎编辑,因为您可能会破坏导入/包含文件的功能。在提交更改之前检查它们。

3.永远不要包含/导入无前缀的文件。

如果您想制作一个 cheeseburger.xsl,请不要包含 hamburger.xsl。相反,包括 i-bread.xsl、i-beef.xsl 和新创建的 i-cheese.xsl。

【讨论】:

【参考方案5】:

为了便于阅读,我使用了xsl:template 标签。它非常简洁易用。将参数传递给模板很简单。这种技术称为封装,是良好编程的基础之一。

【讨论】:

但是在什么情况下你会使用 xsl:template 标签而不是别的东西呢?我看到使用它而不是 xslfor-each 是一个好主意。还有其他情况吗? 很多时候,我使用模板来简单地封装一些功能。如此冗长,XSLT 文件变得非常长非常快。通过将它们切成更小的模板,我发现这些文件更易于维护和调试。如果你有一个循环,那显然是模板的候选者。

以上是关于编写有效的 XSLT的主要内容,如果未能解决你的问题,请参考以下文章

如何编写 XSLT 将 XML 转换为 CSV?

如何在 XSLT 中编写 PHP

如何判断我编写的 XSLT 3.0 是不是实际上是流式传输 XML?

基于 XSD 变化的动态 XSLT 生成

如何运行 XSLT 文件?

XSLT:显示尾随零