使用XSLT作为XML预处理器

时间:2011-08-26 10:54:52

标签: xml xslt preprocessor

这是我第一次使用XSLT或XML做任何事情,所以请原谅。我发现XSLT Web文档非常简洁。

我有一个XML文件,我希望根据一组输入定义来选择性地删除内容。该行为应类似于处理ifdef块的简单代码预处理器。

我已经解决了如何执行如下操作,但是某些部分(例如“内容”变量)似乎不是处理此问题的最佳方法。

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

  <xsl:output method="xml" />
  <xsl:param name="defines-uri" required="yes"/>

  <xsl:template match="* | @*">
  <xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
  </xsl:template>

  <xsl:template match="ifdef">
    <xsl:variable name="contents" select="child::node()"/>
    <xsl:variable name="defines" select="document($defines-uri)/defines"/>
    <xsl:variable name="val" select="@select"/>

    <xsl:for-each select="$defines">
      <xsl:if test="def=$val">
        <xsl:apply-templates select="$contents"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

主要问题是在定义中找到匹配项时的应用模板。如果没有内容,我会在输出中将不同程度的定义文档转储。

什么是在没有转换的情况下对XML进行预处理的最佳方法?

2 个答案:

答案 0 :(得分:1)

  

我已经解决了如何执行如下操作,但是某些部分(例如“内容”变量)似乎不是处理此问题的最佳方法。

嗯,基本上你做对了。不过,你仍然可以改善它:

<xsl:variable name="defines" select="document($defines-uri)/defines"/>

<xsl:template match="ifdef">
  <xsl:variable name="this" select="."/>

  <xsl:for-each select="$defines[def = $this/@select]">
    <xsl:apply-templates select="$this/node()" />
  </xsl:for-each>
</xsl:template>

<xsl:for-each>更改上下文节点。在其中,.指的是被迭代的节点,而不是<xsl:template>匹配的节点。

这意味着您必须在变量中预先设置“外部”上下文,这是标准做法。

答案 1 :(得分:1)

对于刚开始使用XSLT XML的人来说,你做得非常好。

这不是你问题的答案,但我只想说这可能是一个更安全的“默认复制”模板:

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

您的工作是通过某个默认内置模板的优雅。但是,当您添加更多模板时,您可能会对文本节点(或其他非元素的东西)产生奇怪的行为,因为默认值的优先级较低。