2009-04-30 78 views
4

我正在尝试对XML文档进行转换。我的XML变换可导致两种不同类型的底座元件的取决于特定元素的值:空白xmlns =“”来自导入的属性

<StructureA xmlns="http://..."> 

StructureA &:

<xsl:template match="/"> 
    <xsl:choose> 
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'"> 
     <xsl:call-template name="StructureA"> 
     <xsl:with-param name="structure" select="//databean" /> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:call-template name="StructureB"> 
     <xsl:with-param name="structure" select="//databean" /> 
     </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

StructureA或StructureB然后用自己的命名空间和schemaLocations创建B共享一些共同的元素,因此这些元素被定义在一个名为“xmlcommon.xslt”的单独文件中,这两个结构都包含来自这些模板的文件。这个xmlcommon文件没有定义默认名称空间,因为我希望它可以从StructureA或StructureB中定义的名称空间使用。但是,当我跑我的改造,任何模板空白的xmlns从普通文件结果拉到属性:

<StructureA xmlns="http://..."> 
    <SharedElement xmlns="">Something</SharedElement> 
</StructureA> 

验证时,空白的命名空间则用来代替正确的父之一。 有谁知道我可以通过添加这些空白xmlns属性来阻止我的公共文件中的模板吗?

下面是从普通文件的片段:

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template name="ControlledListStructure"> 
    <xsl:param name="xmlElem" /> 
    <xsl:param name="structure" /> 

    <xsl:element name="{$xmlElem}"> 
     <!-- Blah blah blah --> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

回答

9

实现的关键是,你的样式表指示您添加到结果树中的每个元素的名称。元素的名称包含两部分:本地名称和名称空间URI。在上面的代码中,您提供本地名称(值为$xmlElem),但不指定名称空间URI,这意味着它将默认为空字符串。 (实际上,它采用了该样式表模块的默认名称空间;因为没有,所以它是空字符串)。换句话说,该元素将不在名称空间中的。在序列化文档时,XSLT处理器必须包含xmlns=""未声明,以便取消声明顶部出现的默认名称空间。否则,该元素将采用该名称空间,这不是您的样式表规定的。解决这个问题的最少干扰方式是添加另一个参数(例如$namespaceURI),就像您使用$xmlElem一样。然后,你会写:

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}"> 

现在,所产生的元素将采取任何命名空间,你告诉它承担(这将有删除这些默认命名空间未声明的效果)。

这应该回答你的问题。我提供以下免费奖金材料。 ;-)

您应该在您的值比较中删除text()节点测试。很少需要直接比较文本节点的值。相反,您可以比较元素本身的字符串值(它被定义为所有后代文本节点的字符串值的连接)。这将是这样的:

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'"> 

做这种方式是,如果有一个评论躲藏在那里,你的代码不会打破的优点:

<value>2<!--test-->00</value> 

在这种情况下,有两种文本节点(“2”和“00”)。您的原始测试会失败,因为它会检查它们中的任何一个是否等于“200”。在这种情况下不太可能发生,但在任何情况下,测试元素的字符串值(而不是其文本节点子元素)是一种很好的练习,这是您的意图。

最后,我鼓励您了解模板规则和XPath上下文。我倾向于尽可能避免使用<xsl:choose><xsl:call-template><xsl:with-param>。首先,模板规则可以帮助您避免XSLT的许多丑陋的,冗长的部分。

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1"> 
    <StructureA xmlns="http://..."> 
    ... 
    </StructureA> 
</xsl:template> 

<xsl:template match="/databean"> 
    <StructureB xmlns="http://..."> 
    ... 
    </StructureB> 
</xsl:template> 

即使您继续使用<xsl:call-template>,你不应该来传递$structure参数,作为当前节点将在所谓的模板保持不变。因为当前节点仍然是“/”(文档节点),所以您可以从StructureAStructureB模板中轻松访问//databean(或/databean,我怀疑这是您的意思)。

如果您想了解更多关于XSLT的核心处理模式,其最强大的功能(模板规则),那么我建议你从我XSLT 1.0袖珍参考退房"How XSLT Works",免费的样章。

我希望这对你有帮助,即使它比你讨价还价更多!

+0

很好的解释,埃文。没有更多要补充的。从我+1。欢迎来到SO。 – 2009-04-30 13:29:42