XML 文档到 XHTML 文档的 XSLT 转换

发布于 2024-10-27 05:46:37 字数 1415 浏览 0 评论 0原文

这是我的模板:

<xsl:template name="rec">
  <xsl:for-each select="*">
    <div class="{local-name()}">
      <xsl:for-each select="@*">
        <xsl:attribute name="data-{local-name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:for-each>
      <xsl:value-of select="text()" />
      <xsl:call-template name="rec" />
    </div>
  </xsl:for-each>
</xsl:template>

给定一个像这样的文档:

<test>
  <item value="1">Item 1 Text</item>
  <item value="2">Item 2 Text</item>
</test>

上面的转换将把它变成:

<div class="test">
  <div class="item" data-value="1">Item 1 Text</div>
  <div class="item" data-value="2">Item 2 Text</div>
</div>

我遇到的问题是,这个转换没有正确尊重文本节点,而且我没有足够的 XSLT 背景来弄清楚如何修复它。问题是这样的:给定 xml,如下所示:

<para>This is a <emphasis>paragraph</emphasis> people!</para>

我想看到以下输出:

<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>

问题是我没有得到这个 - 我得到了这个:

<div class="para">This is a <div class="emphasis">paragraph</div></div>

注意缺少的“人!”文本节点。如何修复上面的 XSLT 以提供我需要的输出?

Here's my template:

<xsl:template name="rec">
  <xsl:for-each select="*">
    <div class="{local-name()}">
      <xsl:for-each select="@*">
        <xsl:attribute name="data-{local-name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:for-each>
      <xsl:value-of select="text()" />
      <xsl:call-template name="rec" />
    </div>
  </xsl:for-each>
</xsl:template>

Given a document like so:

<test>
  <item value="1">Item 1 Text</item>
  <item value="2">Item 2 Text</item>
</test>

The above transform will turn it into:

<div class="test">
  <div class="item" data-value="1">Item 1 Text</div>
  <div class="item" data-value="2">Item 2 Text</div>
</div>

The problem I'm having, is that this transform doesn't respect text nodes properly, and I don't have enough background with XSLT to figure out how to fix it. Here's the problem: given xml like so:

<para>This is a <emphasis>paragraph</emphasis> people!</para>

I would like to see the following output:

<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>

The problem is that I'm not getting this - I'm getting this:

<div class="para">This is a <div class="emphasis">paragraph</div></div>

Notice the missing 'people!' text node. How can I fix my XSLT above to provide me with the output I need?

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

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

发布评论

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

评论(1

影子是时光的心 2024-11-03 05:46:37

一个问题是

  <xsl:value-of select="text()" />

仅选择第一个子文本节点的值并将其输出。

正确执行此操作的最简单方法可能是使用 而不是

然后,

  <xsl:for-each select="*">

  <xsl:value-of select="text()" />

您可以使用

  <xsl:apply-templates />

来将适当的模板按顺序应用于每个子元素和文本节点,而不是跳过任何模板。

这是一个完整的实现:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">

   <xsl:template match="*">
      <div class="{local-name()}">
         <xsl:for-each select="@*">
            <xsl:attribute name="data-{local-name()}">
               <xsl:value-of select="."/>
            </xsl:attribute>
         </xsl:for-each>
         <xsl:apply-templates />
      </div>
   </xsl:template>

</xsl:stylesheet>

请注意 ,它在没有显式 的情况下默认对上下文节点的所有子节点(包括文本节点)进行操作选择 属性。

默认模板用于文本节点。该模板只是将它们复制到输出中。

示例输入:

<test>
   <item value="1">Item 1 Text</item>
   <item value="2">Item 2 Text</item>
   <para>This is a <emphasis>paragraph</emphasis> people!</para>
</test>

产生所需的输出:

<div class="test">
   <div class="item" data-value="1">Item 1 Text</div>
   <div class="item" data-value="2">Item 2 Text</div>
   <div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
</div>

One problem is that

  <xsl:value-of select="text()" />

just selects the value of the first child text node, and outputs it.

The easiest way to do this right is probably to use <xsl:apply-templates> instead of <xsl:call-template>.

Then instead of

  <xsl:for-each select="*">

and

  <xsl:value-of select="text()" />

you can use

  <xsl:apply-templates />

which will apply the appropriate template to each child element and text node, in order, not skipping any.

Here is a complete implementation:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">

   <xsl:template match="*">
      <div class="{local-name()}">
         <xsl:for-each select="@*">
            <xsl:attribute name="data-{local-name()}">
               <xsl:value-of select="."/>
            </xsl:attribute>
         </xsl:for-each>
         <xsl:apply-templates />
      </div>
   </xsl:template>

</xsl:stylesheet>

Note the <xsl:apply-templates/>, which operates on all children of the context node, including text nodes, by default in absence of an explicit select attribute.

A default template is used for text nodes. This template simply copies them to the output.

Sample input:

<test>
   <item value="1">Item 1 Text</item>
   <item value="2">Item 2 Text</item>
   <para>This is a <emphasis>paragraph</emphasis> people!</para>
</test>

produces the desired output:

<div class="test">
   <div class="item" data-value="1">Item 1 Text</div>
   <div class="item" data-value="2">Item 2 Text</div>
   <div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
</div>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文