4

我编写了一个用于将 XML 转换为 ePub 的包。一切正常,除了某些情况下,空白命名空间 ( xmlns="") 节点被写入结果文档。在转换之前,我准备了用于保存主段(即,等)的临时变量,meta最后body将节点(使用xsl:copy-of[@copy-namespaces='no']指令)复制到结果文档。我也在元素内使用过@exclude-result-prefixes='ns_list_sep_by_space'xsl:transform但仍然无法获得预期的结果。

oXygen IDE 在弹出窗口中显示一条消息:

当使用 xsl:copy-of 时,新元素还将具有从原始元素节点复制的命名空间节点,除非通过指定 copy-namespaces="no" 将它们排除在外。如果此属性被省略,或者取值为 yes,则原始元素的所有命名空间节点都将复制到新元素。如果它的值为 no,则不会复制任何命名空间节点:但是,命名空间节点仍将根据命名空间修复过程的要求在结果树中创建。


这是我的问题的更多详细信息:

主要样式表:
main.xsl:main caller

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
    xmlns:cylian="local-ns-for-extension-functions"
    exclude-result-prefixes="xs xd cylian"
    version="2.0">

    <xsl:import href="modules/core.xsl"/>

    <xsl:variable name="base" select="base-uri()" as="xs:anyURI"/>

    <xsl:template match="/">
        <xsl:call-template name="procA"/>
    </xsl:template>

</xsl:transform>

主要样式表:
core.xsl: core processing unit

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
        xmlns:cylian="local-ns-for-extension-functions"
        exclude-result-prefixes="xs xd cylian"
        version="2.0">

      <xsl:import href="sub1.xsl"/>  
      <xsl:import href="sub2.xsl"/>  
      <!--and more-->  

      <!-- variable to hold intermediate results for stage1 -->
      <xsl:variable name="stage1">
          <cylianz>
              <xsl:copy-of select="$a" copy-namespaces="no"/>
              <xsl:copy-of select="$b" copy-namespaces="no"/>
              <!--and more-->
          </cylianz>
      </xsl:variable>

      <!-- variable to hold intermediate results for stage2 -->
      <xsl:variable name="stage2">
          <cylianz>
            <xsl:for-each select="$stage1//cylian">
                <xsl:sort select="@pos"/>
                <xsl:sequence select="."/>
            </xsl:for-each>
          </cylianz>
      </xsl:variable>
      <xsl:template name="procA">
          <xsl:for-each select="$stage2//cylian">
              <xsl:result-document href="{concat($outdir,@href)}" format="general">
                  <xsl:call-template name="procB">
                        <xsl:with-param name="context" select="."/>
                        <xsl:with-param name="title">
                            <xsl:value-of select="$book_title"/>
                        </xsl:with-param>
                   </xsl:call-template>
              </xsl:result-document>
          </xsl:for-each>
      </xsl:template>
     <xsl:template name="procB">
         <xsl:param name="context"/>
         <xsl:param name="title"/>
         <html xmlns="http://www.w3.org/1999/xhtml">
         <head>
              <xsl:call-template name="header">
                  <xsl:with-param name="title" select="$title"/>
               </xsl:call-template>
         </head>
         <body>
              <div id="root">
                  <xsl:apply-templates select="."/>
              </div>
         </body>
    </html>
</xsl:template>

<!--
 1/ other rules are shortened for clarity
 2/ declaration «xmlns:cylian='local-ns-for-extension-functions'» has to retain, some parts of transformation uses some extension functions from that namespace
-->

</xsl:transform>

这是输出: a.html

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
  PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta xmlns="" http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
      <title xmlns="">BookTitle</title>
          <!--
              2012.04.16 - 18:27:36 [XSLT processor: SAXON 9.1.0.5 from Saxonica]
          -->
      <link xmlns="" href="isbn.css" type="text/css" rel="stylesheet"/>
   </head>
   <body>
      <div id="root">
         <div xmlns="" id="a1">
            <!--...-->
         </div>
      </div>
   </body>
</html>

我希望它会更容易理解发生了什么问题。欢迎所有建议。提前致谢。

4

3 回答 3

5

好吧,我们需要确定您的代码,但我怀疑您有例如

<xsl:template match="/">
  <foo xmlns="http://example.com/ns">
    <xsl:apply-templates/>
  </foo>
</xsl:template>

<xsl:template match="whatever">
  <bar/>
</xsl:template>

然后你得到

<foo xmlns="http://example.com/ns">
  <bar xmlns=""/>
</foo>

当你想要的时候

<foo xmlns="http://example.com/ns">
  <bar/>
</foo>

要解决这个问题,请确保您在 xsl:stylesheet 元素上移动默认命名空间声明,例如

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

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

    <xsl:template match="whatever">
      <bar/>
    </xsl:template>

</xsl:stylesheet>

这样,它适用于在不同模板中创建的所有结果元素。

[编辑]根据您现在提供的示例,我认为我的建议是正确的,只有几个文件您需要确保您已将所有样式表模块放在xmlns="http://www.w3.org/1999/xhtml"相应的xsl:stylesheet元素上xsl:transform,以便所有结果元素最终都位于 XHTML 命名空间中。

[第二次编辑]我想你想要

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
        xmlns:cylian="local-ns-for-extension-functions"
        exclude-result-prefixes="xs xd cylian"
        version="2.0">

      <xsl:import href="sub1.xsl"/>  
      <xsl:import href="sub2.xsl"/>  
      <!--and more-->  

      <!-- variable to hold intermediate results for stage1 -->
      <xsl:variable name="stage1" xmlns="">
          <cylianz>
              <xsl:copy-of select="$a" copy-namespaces="no"/>
              <xsl:copy-of select="$b" copy-namespaces="no"/>
              <!--and more-->
          </cylianz>
      </xsl:variable>

      <!-- variable to hold intermediate results for stage2 -->
      <xsl:variable name="stage2" xmlns="">
          <cylianz>
            <xsl:for-each select="$stage1//cylian">
                <xsl:sort select="@pos"/>
                <xsl:sequence select="."/>
            </xsl:for-each>
          </cylianz>
      </xsl:variable>
      <xsl:template name="procA">
          <xsl:for-each select="$stage2//cylian">
              <xsl:result-document href="{concat($outdir,@href)}" format="general">
                  <xsl:call-template name="procB">
                        <xsl:with-param name="context" select="."/>
                        <xsl:with-param name="title">
                            <xsl:value-of select="$book_title"/>
                        </xsl:with-param>
                   </xsl:call-template>
              </xsl:result-document>
          </xsl:for-each>
      </xsl:template>
     <xsl:template name="procB">
         <xsl:param name="context"/>
         <xsl:param name="title"/>
         <html >
         <head>
              <xsl:call-template name="header">
                  <xsl:with-param name="title" select="$title"/>
               </xsl:call-template>
         </head>
         <body>
              <div id="root">
                  <xsl:apply-templates select="."/>
              </div>
         </body>
    </html>
</xsl:template>


</xsl:transform>

然后,如果您有任何额外的模块应该生成 XHTML 元素,请确保您放置xmlns="http://www.w3.org/1999/xhtml"在模块的根元素上,或者如果您需要在其他名称空间中创建元素以及任何应该输出 XHTML 的模板。

于 2012-04-16T11:47:35.163 回答
3

输出中可能会出现两种“不需要的”命名空间声明:不需要的声明,因为它们是多余的噪音(它们声明了未使用的命名空间前缀),以及不需要的声明,因为它们将元素放在与预期的命名空间不同。

在第一种情况下,XSLT 提供了诸如 exclude-result-prefixes 和 copy-namespaces='no' 之类的特性来消除噪音。

在第二种情况下(我认为你是这样的),命名空间声明是样式表作者首先在错误的命名空间中创建元素这一事实的症状,解决方案是查看创建的代码元素,并修复它。例如<foo>,当您打算<foo xmlns="something"/>在其他命名空间中创建元素时,您可能编写了一个文字结果元素,该元素在非命名空间中创建元素。

于 2012-04-16T11:59:02.297 回答
3

让我们拥有这个 XML 文档

<x:t xmlns:x="some:x">
 <a/>
 <b/>
</x:t>

这是可能与您的代码相似的代码

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

    <xsl:template match="/*">
      <t xmlns="some:x">
        <xsl:copy-of select="*" copy-namespaces="no"/>
      </t>
    </xsl:template>
</xsl:stylesheet>

它会产生这种不需要的结果

<t xmlns="some:x">
   <a xmlns=""/>
   <b xmlns=""/>
</t>

为什么会产生这个结果?

因为您使用<xsl:copy-of>的节点是“按原样”复制的,所以元素不会更改它们所在的命名空间。该属性copy-namespaces="no"仅指定属于该元素的命名空间节点将被跳过复制——而不是该元素将改变自己的命名空间。

解决方案

当我们想要更改元素所在的命名空间时(在本例中从“no namespace”更改为“some:x”,我们不应该复制此元素节点。

相反,我们必须从这个元素中创建一个新元素,并指定新元素应该位于的新命名空间:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

    <xsl:template match="/*">
      <t xmlns="some:x">
        <xsl:apply-templates select="*"/>
      </t>
    </xsl:template>

    <xsl:template match="*">
      <xsl:element name="{local-name()}" namespace="some:x">
        <xsl:apply-templates select="node() | @*"/>
      </xsl:element>
    </xsl:template>
</xsl:stylesheet>

当此转换应用于同一个 XML 文档(如上)时,会产生所需的正确结果

<t xmlns="some:x">
   <a/>
   <b/>
</t>
于 2012-04-16T12:53:37.967 回答