【问题标题】:Remove namespace declaration from XSLT stylesheet with XSLT使用 XSLT 从 XSLT 样式表中删除命名空间声明
【发布时间】:2012-09-18 22:23:09
【问题描述】:

我有一个 XSLT 样式表,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                  xmlns:XQHeaderFunc="java:com.sonicsw.xq.service.xform.HeaderExtension"
                  xmlns:saxon="http://saxon.sf.net/">

  <saxon:script language="java" implements-prefix="XQHeaderFunc" src="java:com.sonicsw.xq.service.xform.HeaderExtension" />

  <xsl:output indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="/">
    <xsl:variable name="processId" select="XQHeaderFunc:getProperty(XQHeaderFunc:new(),'processId',-1)" />
    <xsl:value-of select="XQHeaderFunc:setProperty(XQHeaderFunc:new(),'processId',string(@id),-1)"/>

    <root>
      <xsl:apply-templates />
    </root>

  </xsl:template>

  <!-- Other stuff -->

</xsl:stylesheet>

我想使用第二个 XSLT 样式表转换此样式表,以删除与 XQHeaderFunc 和 saxon 命名空间有关的任何内容。有什么办法可以做到吗?


我现在尝试了以下方法,成功处理了元素,但命名空间声明似乎不想消失。

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:XQHeaderFunc="java:com.sonicsw.xq.service.xform.HeaderExtension"
                xmlns:saxon="http://saxon.sf.net/"
                exclude-result-prefixes="XQHeaderFunc saxon">

  <xsl:param name="XQHeaderReplacement" />
  <xsl:variable name="apos">'</xsl:variable>

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

  <!-- Remove saxon script tag -->
  <xsl:template match="saxon:script" />

  <!-- Remove elements with setProperty calls -->
  <xsl:template match="*[starts-with(@select, 'XQHeaderFunc:setProperty')]" />

  <!-- Replace getProperty calls with replacement value-->
  <xsl:template match="@select[starts-with(., 'XQHeaderFunc:getProperty')]">
      <xsl:attribute name="select">
        <xsl:value-of select="concat($apos, $XQHeaderReplacement, $apos)"/>
      </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:XQHeaderFunc="java:com.sonicsw.xq.service.xform.HeaderExtension" 
                xmlns:saxon="http://saxon.sf.net/">

  <xsl:output indent="yes" omit-xml-declaration="yes" />

  <xsl:template match="/">
    <xsl:variable name="processId" select="''" />


    <root>
      <xsl:apply-templates />
    </root>

  </xsl:template>

  <!-- Other stuff -->

</xsl:stylesheet>

【问题讨论】:

  • 请提供完整的源 XML 文档(第一个样式表)。有些操作必须完成,而您似乎并不知道。通常,简单地删除命名空间声明会导致非(命名空间)格式良好的结果,XSLT 处理器将通过生成新的命名空间声明来防止这种情况发生。
  • 用更具体的来源和我现在尝试过的新示例更新了问题。
  • 您的更新很有帮助,但请发布您从转换中获得的实际结果。这将帮助我们准确了解它的外观,以便我们可以帮助找出为什么它仍然具有 ns decl。
  • 添加了两个 xslt 文件的确切来源以及在 Visual Studio 2012 中运行后的输出来源。
  • 好的,谢谢。看着它。为什么删除命名空间声明对您如此重要?您知道它应该对输出 XML 的语义没有有意义的影响,对吧?

标签: xslt xslt-1.0 xml-namespaces


【解决方案1】:

我会补充

 exclude-result-prefixes="foo"

到你的

 <xsl:stylesheet>

元素。然后,如果可能,foo 的命名空间声明将被省略,即如果该命名空间中没有要输出的元素或属性。

仅供参考,这行的原因

<xsl:template match="xsl:stylesheet/@xmlns:foo" />`

抛出错误是因为输入文档中的xmlns:foo不是属性;这是一个伪属性。您的匹配模式要求匹配的是名为foo 的属性,该属性位于与命名空间前缀xmlns 对应的命名空间中。由于您没有在样式表中声明命名空间前缀 xmlns,因此您会收到错误“prefix xmlns is not defined”。

更新:

我从您发布的输出(以及我自己的测试)中看到 exclude-result-prefixes 在删除命名空间声明方面没有效果。

1) 首先我要问为什么它很重要。它不会更改输出 XSLT 中任何内容的名称空间。您只是出于美观的原因而试图将其删除吗?

2) 看着&lt;xsl:copy&gt; 不理会exclude-result-prefixes 的XSLT 1.0 spec, it appears to me:

实例化 xsl:copy 元素会创建当前节点的副本。 当前节点的命名空间节点自动复制为 嗯……

AFAICT,只有文字结果元素会省略基于 exclude-result-prefixes 的命名空间节点。

在此基础上,我会尝试用&lt;xsl:element name="{name()}"&gt; 或其某种变体替换您的身份模板(用于元素)中的&lt;xsl:copy&gt;。然后,您需要为非元素节点创建一个单独的标识模板。

我将您的身份模板替换为以下两个模板:

<!-- Copy elements -->
<xsl:template match="*" priority="-1">
   <xsl:element name="{name()}">
      <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
</xsl:template>

<!-- Copy all other nodes -->
<xsl:template match="node()|@*" priority="-2">
   <xsl:copy />      
</xsl:template>

这给出了我认为是期望的输出,没有多余的 ns 声明:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output indent="yes" omit-xml-declaration="yes" />

   <xsl:template match="/">
      <xsl:variable name="processId" select="''" />
      <root>
         <xsl:apply-templates />
      </root>
   </xsl:template>

   <!-- Other stuff -->
</xsl:stylesheet>

(为了清晰起见,我调整了空格。)

【讨论】:

  • 这会删除所有命名空间吗?我只是对删除这两个特别感兴趣。但是,是的,现在我已经设法删除了实际元素等,这并不是很重要。更像是一种烦恼:p
  • @Svish:(为清楚起见,请区分“命名空间”和 ns declarations 或 ns prefixes。)测试它。输出仍然是命名空间格式良好的。上述转换不会删除命名空间:请注意&lt;xsl:template&gt; 仍在“XSL/Transform”命名空间中。它也不会删除 needed ns declarations。如果您希望保留一些 unneeded ns 声明,则可能必须显式复制相关的命名空间节点,但这比想要 remove 更没有意义i> 不必要的 ns 声明。
  • 似乎完美运行!非常感谢。 (我会尽量记住那个肯定会让事情更清楚的区别:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-26
  • 1970-01-01
  • 1970-01-01
  • 2015-05-04
  • 2012-08-16
  • 1970-01-01
相关资源
最近更新 更多