2010-07-21 61 views
1

我试图执行XSD文件的XSLT转换。我的目标是最终从XSD创建SQL。到目前为止好,这是我有:XSLT转换创建StackoverflowException

void Convert() 
{ 
      XPathDocument xpathDoc = new XPathDocument(@"myschema.xsd"); 
      string xslPath = @"convert.xsl"; 
      XslCompiledTransform transform = new XslCompiledTransform();    
      transform.Load(xslPath, new XsltSettings(true, true), null);  
      using (FileStream fs = File.Create(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "output.sql"))) 
      { 
       try 
       { 
        transform.Transform(xpathDoc, null, fs); 
       } 
       catch 
       { 
        fs.Close(); 
       } 
      } 
} 

这是一个失败的XSLT文件:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       version="1.0" 
       xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

<!-- Get schema nodes from this schema and any included schemas --> 
<xsl:variable name="contents" select="/|document(//xs:include/@schemaLocation)" /> 

<xsl:template match="*" > 

<xsl:for-each select="$contents" > 
    <xsl:apply-templates select=".//xs:element" /> 
</xsl:for-each> 

</xsl:template> 

<xsl:template match="xs:element"> 

    <xsl:apply-templates /> 

</xsl:template> 

</xsl:stylesheet> 

我总是得到StackoverflowException在System.Data.SqlXml.dll。我怎样才能停止递归?如果不存在xs:元素,它不应该停止吗?

编辑: 原始代码是从here它已经有错误。我试图通过简化XSLT来修复它,直到只剩下错误。

+0

你的样式表应该做什么?您发布的样本没有任何意义,因为它不会输出任何内容。它基本上是对同一个模板的递归“调用”,因此产生了一个SOE。 – 2010-07-21 14:09:38

+0

在我的问题结尾处看到我的编辑 – codymanix 2010-07-21 14:29:28

回答

4

线

<xsl:apply-templates select=".//xs:element" /> 

发送当前节点(XS:元素),将其从开始的模板。然后它在for循环中匹配并重新发送。堆栈溢出是不可避免的。

0

正如伍迪回答,您有一个通知(“对于每个元素...应用模板元素”)。所以,正确的做法是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xsl:template match="/" name="root"> 
     <xsl:param name="schema" select="*/*"/> 
     <xsl:choose> 
      <xsl:when test="$schema[self::xs:include]"> 
       <xsl:call-template name="root"> 
        <xsl:with-param name="schema" select="$schema[not(self::xs:include)]|document($schema[self::xs:include]/@schemaLocation)/*/*"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="*/*"> 
        <xsl:with-param name="schema" select="$schema"/> 
       </xsl:apply-templates> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

有了这个样式表,您需要使用您已经扩展架构PARAM schema添加您的模板。此外,您需要将参数schema作为select="$schema"应用模板。

编辑:对不起,有点小错。此外,还有一个解释:当您处理模块化模式时,您需要首先获取完整的扩展模式,否则最终会调用递归模板来每次在不同的模式模块中获取参考和类型定义。使用我的模板,您可以在$schema param中获得完整的展开架构,因此当您使用@type="someType"处理xs:element时,可以使用xsl:apply-templates select="$schema[self::xs:complexType[@name='someType']]"继续此过程。

0

导致无限递归的问题是在这里:

<xsl:template match="xs:element"> 

    <xsl:apply-templates /> 

</xsl:template> 

<xsl:apply-templates>指令将导致其它元素比的xs:要被处理元件。对于所有这些元素,选择以下模板进行处理:

<xsl:template match="*" >  

<xsl:for-each select="$contents" >  
    <xsl:apply-templates select=".//xs:element" />  
</xsl:for-each>  

</xsl:template> 

并且这会关闭循环并导致无限递归。

这个问题可以被避免以下列方式:

<xsl:template match="xs:include"> 
    <xsl:apply-templates select="document(@schemaLocation)/*/> 
    </xsl:template> 

没有其他特殊模板是必要的 - 只是添加处理特定XSD元素的模板。

+0

您的答案是endles递归的最佳解释。但它不包含“从此架构和任何包含的架构中获取架构节点”部分。 – 2010-07-21 20:28:57

+0

@Alejandro:谢谢,我想我现在已经修好了。 – 2010-07-21 20:55:54