apply-templates输出的内容比预期的多

时间:2015-10-13 04:17:38

标签: xslt apply-templates

我是XSLT的新手,我无法理解为什么根被处理两次(至少这是我对此输出的解释)。

编辑 :(我使用Saxon-HE和XSLT 2.0),但也通过多个在线流程进行测试,结果总是相同。

XSLT文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- XResume.xsl: resume.xml ==> resume.xhtml -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="https://github.com/IME-SE8/XResume">

<xsl:output method="html"/>

<xsl:template match="/">

<html>
<head>
  <meta charset="utf-8" />
  <meta lang="en" />
  <meta name="description" content="Personal Resume and Portfolio" />
  <title><xsl:value-of select="resume/personalInformation/name/attribute::shortForm" /> Website</title>
</head>
<body>
  <xsl:apply-templates select="resume"/>
</body>
</html>

</xsl:template>

<xsl:template match="resume">
  <div class="resume">

    <div class="header">
      <div class="name"><xsl:value-of select="personalInformation/name" /></div>
      <div class="contacts">
        <xsl:for-each select="personalInformation/contact">
          <div class="contactInformation">
            <p><xsl:value-of select="organization" /></p>
            <p><xsl:value-of select="address" /></p>
            <p><xsl:value-of select="phoneNumber" /></p>
            <p><xsl:value-of select="email" /></p>
          </div>
        </xsl:for-each>
      </div>
    </div>

    <div class="sections">
      <xsl:apply-templates />
    </div>
  </div>
</xsl:template>


<xsl:template match="interests"></xsl:template>
<xsl:template match="education"></xsl:template>
<xsl:template match="skills"></xsl:template>
<xsl:template match="experiences"></xsl:template>
<xsl:template match="projects"></xsl:template>
<xsl:template match="awards"></xsl:template>

</xsl:stylesheet>

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl"
href="https://github.com/IME-SE8/XResume/master/XResume.xsl"?>
<resume 
xmlns="https://github.com/IME-SE8/XResume" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/IME-SE8/XResume XResume.xsd">

    <personalInformation>
        <name first="John" last="Doe" shortForm="JD">John Doe</name>
        <contact type="institutional">
            <organization>StackOverflow Institute of Technology</organization>
            <address>Internet</address>
            <phoneNumber>+1 (666) 666-9999</phoneNumber>
            <email>john@d.oe</email>
        </contact>
    </personalInformation>


    <interests>
        <interest>Q and A</interest>
        <interest>XSLT</interest>
    </interests>

    <education></education>

    <skills></skills>

    <experiences></experiences>

    <projects></projects>

    <awards></awards>

</resume>

HTML输出

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta charset="utf-8">
      <meta lang="en">
      <meta name="description" content="Personal Resume and Portfolio">
      <title>JD Website</title>
   </head>
   <body>
      <div class="resume">
         <div class="header">
            <div class="name">John Doe</div>
            <div class="contacts">
               <div class="contactInformation">
                  <p>StackOverflow Institute of Technology</p>
                  <p>Internet</p>
                  <p>+1 (666) 666-9999</p>
                  <p>john@d.oe</p>
               </div>
            </div>
         </div>
         <div class="sections">


                    John Doe

                        StackOverflow Institute of Technology
                        Internet
                        +1 (666) 666-9999
                        john@d.oe

















         </div>
      </div>
   </body>
</html>

(是的,有这么多空行)

输出header div非常好,但在sections divapply-templates再次呈现div header中的所有信息,但没有HTML标记。

我缺少任何XSLT处理细节吗?模板匹配是否以匹配元素现在被视为根或类似的方式设置上下文?

3 个答案:

答案 0 :(得分:1)

问题在于:

<div class="sections">
  <xsl:apply-templates />
</div>

这会将模板应用于当前节点(resume)的所有子节点,包括personalInformation元素。

由于没有为personalInformation指定匹配模板,XSLT处理器使用内置XSLT模板并应用它们导致输出personalInformation元素的所有后代文本节点的串联。

<强>解决方案

替换:

<div class="sections">
  <xsl:apply-templates />
</div>

使用:

<div class="sections">
  <xsl:apply-templates select="*[not(self::personalInformation)]" />
</div>

转换的结果现在不包含所提出的有问题的输出:

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta charset="utf-8">
      <meta lang="en">
      <meta name="description" content="Personal Resume and Portfolio">
      <title>JD Website</title>
   </head>
   <body>
      <div class="resume">
         <div class="header">
            <div class="name">John Doe</div>
            <div class="contacts">
               <div class="contactInformation">
                  <p>StackOverflow Institute of Technology</p>
                  <p>Internet</p>
                  <p>+1 (666) 666-9999</p>
                  <p>john@d.oe</p>
               </div>
            </div>
         </div>
         <div class="sections"></div>
      </div>
   </body>
</html>

答案 1 :(得分:0)

您尚未提供预期的输出,因此我会猜测您的预期结果。这是一个XSLT 2.0解决方案。如果您需要XSLT 1.0,请发表评论,我可以添加。但请记住,如果您的转换引擎是浏览器,您没有理由不使用XSLT 2.0。 (参考Saxon CE)。

XSLT 2.0解决方案

这个XSLT 2.0样式表......

<xsl:transform
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:r="https://github.com/IME-SE8/XResume" 
    exclude-result-prefixes="r"
    version="2.0">

<xsl:output method="html" version="5" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />

<xsl:template match="/">
  <html>
    <head>
      <meta lang="en" />
      <meta name="description" content="Personal Resume and Portfolio" />
      <title><xsl:value-of select="r:resume/r:personalInformation/r:name/@shortForm" /> Website</title>
    </head>
    <body>
      <xsl:apply-templates select="r:resume"/>
    </body>
  </html>
</xsl:template>

<xsl:template match="r:resume">
  <div class="resume">
    <div class="header">
      <div class="name"><xsl:value-of select="r:personalInformation/r:name" /></div>
      <div class="contacts">
        <xsl:apply-templates select="r:personalInformation/r:contact" />
      </div>
    </div>
    <div class="sections">
      <xsl:apply-templates select="* except r:personalInformation" />
    </div>
  </div>      
</xsl:template>

<xsl:template match="r:contact">
  <div class="contactInformation">
    <xsl:apply-templates />
  </div>
</xsl:template>

<xsl:template match="r:organization|r:address|r:phoneNumber|r:email">
  <p><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="r:education|r:skills|r:experiences|r:projects|r:awards">
  <h2><xsl:value-of select="local-name()" /></h2>
  <p><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="r:interests">
  <h2>interests</h2>
  <ul>
    <xsl:apply-templates />
  </ul>
</xsl:template>

<xsl:template match="r:interest">
  <li>
    <xsl:value-of select="." />
  </li>
</xsl:template>

<xsl:template match="*" />

</xsl:transform>

...当应用于此输入文档时......

<resume 
    xmlns="https://github.com/IME-SE8/XResume" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://github.com/IME-SE8/XResume XResume.xsd">

    <personalInformation>
        <name first="John" last="Doe" shortForm="JD">John Doe</name>
        <contact type="institutional">
            <organization>StackOverflow Institute of Technology</organization>
            <address>Internet</address>
            <phoneNumber>+1 (666) 666-9999</phoneNumber>
            <email>john@d.oe</email>
        </contact>
    </personalInformation>


    <interests>
        <interest>Q and A</interest>
        <interest>XSLT</interest>
    </interests>

    <education></education>

    <skills></skills>

    <experiences></experiences>

    <projects></projects>

    <awards></awards>

</resume>

...将产生此输出html页面....

<!DOCTYPE HTML>
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta lang="en">
      <meta name="description" content="Personal Resume and Portfolio">
      <title>JD Website</title>
   </head>
   <body>
      <div class="resume">
         <div class="header">
            <div class="name">John Doe</div>
            <div class="contacts">
               <div class="contactInformation">
                  <p>StackOverflow Institute of Technology</p>
                  <p>Internet</p>
                  <p>+1 (666) 666-9999</p>
                  <p>john@d.oe</p>
               </div>
            </div>
         </div>
         <div class="sections">
            <h2>interests</h2>
            <ul>
               <li>Q and A</li>
               <li>XSLT</li>
            </ul>
            <h2>education</h2>
            <p></p>
            <h2>skills</h2>
            <p></p>
            <h2>experiences</h2>
            <p></p>
            <h2>projects</h2>
            <p></p>
            <h2>awards</h2>
            <p></p>
         </div>
      </div>
   </body>
</html>

说明:为什么要进行两次根处理

简而言之,因为您的<div class="sections"><xsl:apply-templates /></div>指令未指定select属性。应用默认选择,此时是文档根目录。

答案 2 :(得分:0)

源文档中的所有元素都在命名空间中,但是样式表是在没有命名空间的情况下编写的。欢迎来到俱乐部,加入其他1000万陷入困境的人们。基本上,您恢复元素与match =“resume”模板不匹配,因此默认模板启动,这将输出没有标记的原始文本。对于该解决方案,搜索“XSLT默认命名空间”并选择大约1000个答案中的任何一个。

重新阅读时,我发现您使用了xpath-default-namespace="https://github.com/IME-SE8/XResume",如果您使用的是XSLT 2.0处理器,则可以解决问题;如果您使用的是XSLT 1.0处理器,则会触发错误。因此,告诉我们您使用的是哪种处理器以及如何运行它可能很有用(实际上,它总是很有用)。