2010-07-21 40 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