使用 XSLT 作为 XML 预处理器

发布于 2024-12-01 16:32:00 字数 1126 浏览 0 评论 0原文

这是我第一次使用 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 进行预处理的最佳方法是什么?

This is my first time doing anything with XSLT, or XML really, so please excuse me. I've found XSLT web documentation is really terse.

I have an XML file that I want to process to selectively drop content based on an input set of defines. The behavior should be similar to a simple code pre-processor handling ifdef blocks.

I've worked out how to do it as below, but some parts such as the "contents" variable didn't seem like the best way to handle this.

<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>

The main issue was the apply-templates on the case when a match was found in the defines. Without the contents, I get the defines document dumped to different degrees in the output.

Whats the best way to do pre-processing of XML without transformation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

殊姿 2024-12-08 16:32:00

我已经弄清楚了如何做到这一点,如下所示,但某些部分(例如“contents”变量)似乎不是处理此问题的最佳方法。

嗯,基本上你是对的。不过,您仍然可以对其进行一些改进:

<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>

更改上下文节点。在其中,. 指的是正在迭代的节点,而不是由 匹配的节点。

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

I've worked out how to do it as below, but some parts such as the "contents" variable didn't seem like the best way to handle this.

Well, basically you got it right. You can still improve it a little, though:

<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>

The <xsl:for-each> changes the context node. Within it, the . refers to the node being iterated over, not the one that had been matched by the <xsl:template>.

That means you have to preseve the "outer" context in a variable, this is standard practice.

倥絔 2024-12-08 16:32:00

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

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

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

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

You're doing really well for someone who's only just beginning with XSLT and XML.

This isn't an answer to your question, but I just wanted to say that this might be a safer "copy by default" template:

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

Yours works by grace of a certain default built-in template. But you might get strange behaviour regarding text nodes (or other things that aren't elements) when you add more templates, since the default has a low priority.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文