XSLT关闭父标记,修复格式错误的HTML

时间:2014-01-22 10:10:11

标签: html xml html5 xslt

假设我有以下XML输入:

<para>
  text before
  <sometag>Content</sometag>
  text after
</para>

我希望将此内容转换为HTML。我有以下两个XSLT规则:

<xsl:template match="para">
  <p>
   <xsl:apply-templates />
  </p>
</xsl:template>

<xsl:template match="sometag">
  <div>
   <xsl:apply-templates />
  </div>
</xsl:template>

输入XML已修复。我目前的知识确实没有解决方法,“sometag”需要转换为div HTML元素。显然,这不是他常见或推荐使用,但它是DTD允许的。这将导致以下输出:

<p>
 text before
 <div>
  Content
 </div>
 text after
</p>

这当然是无效的HTML,因为“p”不能包含“div”。

如果我在浏览器中打开包含此类无效XML的文件,它会自动将此格式错误的HTML自动修复为:

<p>
 text before
</p>
<div>
 Content
</div>
<p>
 text after
</p>

当然,这里发生的是“p”元素在“div”元素开始之前被关闭了。

请注意输出应为HTML5。

我的问题是,是否可以在XSLT2.0中执行此操作?如果没有,是否有任何Java库可以做到这一点?如果是这样,请添加一个示例,我已经看到了类似的问题,但答案只是一个图书馆的链接,似乎没有人这样做。

3 个答案:

答案 0 :(得分:1)

编写一个匹配text()个元素节点的模板。这样,您可以利用这样的事实:当一个子元素属于一个元素的文本内容时,这会导致该元素的几个文本节点。

因此,您实际显示的para元素的内容是:

[text node, "text before"] [sometag node] [text node, "text after"]

<强>样式表

<?xml version="1.0" encoding="utf-8"?>

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

   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/">
      <xsl:apply-templates/>
   </xsl:template>

   <xsl:template match="para|sometag">
         <xsl:apply-templates />
   </xsl:template> 

   <xsl:template match="text()">
      <xsl:choose>
         <xsl:when test="parent::sometag">
            <div>
               <xsl:value-of select="."/>
            </div>
         </xsl:when>

         <xsl:when test="parent::para">
            <p>
               <xsl:value-of select="."/>
            </p>
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="."/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

</xsl:stylesheet>

<强>输出

<?xml version="1.0" encoding="UTF-8"?>
<p>
  text before
  </p>
<div>Content</div>
<p>
  text after
</p>

答案 1 :(得分:1)

使用XSLT 2.0,我认为您希望将匹配para的模板替换为

<xsl:template match="para">
  <xsl:for-each-group select="node()" group-ending-with="sometag">
    <p>
      <xsl:apply-templates select="current-group()[not(self::sometag)]"/>
    </p>
    <xsl:apply-templates select="current-group()[last() and self::sometag]"/>
  </xsl:for-each-group>
</xsl:template>

答案 2 :(得分:1)

这是另一个版本

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

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

    <xsl:template match="para">
        <xsl:for-each-group select="node()" group-adjacent="if (self::text()) then 1 else 0">
            <xsl:choose>
                <xsl:when test="current-grouping-key()">
                    <p>
                        <xsl:apply-templates select="current-group()"/>
                    </p>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="sometag">
        <div>
            <xsl:apply-templates />
        </div>
    </xsl:template>
</xsl:stylesheet>

应用于您输入时:

<para>
  text before
  <sometag>Content</sometag>
  text after
</para>

产生

<p>
    text before
    </p><div>Content</div><p>
    text after
</p>