简体   繁体   English

XSLT转换创建StackoverflowException

[英]XSLT transform creates StackoverflowException

I tried to perform XSLT transform of a XSD file. 我试图执行XSD文件的XSLT转换。 My goal is in the end to create SQL from XSD. 我的目标是最终从XSD创建SQL。 So far so good, this is what I have: 到目前为止一切顺利,这就是我所拥有的:

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();
                }
            }
}

This is the XSLT file which is failing: 这是失败的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>

I always get a StackoverflowException in System.Data.SqlXml.dll. 我总是在System.Data.SqlXml.dll中得到StackoverflowException。 How can I stop the recursion? 我怎么能停止递归? Shouldn't it stop if no xs:element remain? 如果没有xs:元素,它不应该停止吗?

EDIT: The original code was from here and it already had the error. 编辑:原始代码来自这里 ,它已经有错误。 I tried to fix it by simplifying the XSLT until only the error remained. 我试图通过简化XSLT来解决它,直到只剩下错误。

the line 这条线

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

sends the current node (xs:element) to the template it started from. 将当前节点(xs:element)发送到它开始的模板。 Then it matches it in the for loop and sends itself again. 然后它在for循环中匹配它并再次发送自己。 Stack overflow is inevitable. 堆栈溢出是不可避免的。

As Woody has answer, you have a circular call ("For every element... apply templates for elements"). 正如伍迪所回答的那样,你有一个循环调用(“为每个元素......应用元素模板”)。 So, the proper way is: 所以,正确的方法是:

<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>

With this stylesheet you need to add your templates with param schema been your expanded schema. 使用此样式表,您需要使用param schema添加模板作为扩展架构。 Also, you need to apply templates with a param schema as select="$schema" . 此外,您需要将模板与param schema一起应用为select="$schema"

EDIT : Sorry, a little mistake. 编辑 :对不起,有点错误。 Also, an explanation: when you process a modular schema you need to get first the complete expanded schema because otherwise you end up calling a recursion template for getting reference and type definitions in diferent schema modules every time. 另外,解释一下:当您处理模块化模式时,您需要首先获得完整的扩展模式,否则您最终会调用一个递归模板,以便每次都在不同的模式模块中获取引用和类型定义。 With my template you get the complete expanded schema in $schema param, so when you process a xs:element with @type="someType" you could continue the process with xsl:apply-templates select="$schema[self::xs:complexType[@name='someType']]" . 使用我的模板,您可以在$schema param中获得完整的扩展模式,因此当您使用@type="someType"处理xs:element ,您可以使用xsl:apply-templates select="$schema[self::xs:complexType[@name='someType']]"继续该过程xsl:apply-templates select="$schema[self::xs:complexType[@name='someType']]"

The problem that causes the endless recursion is here: 导致无限递归的问题在这里:

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

    <xsl:apply-templates />  

</xsl:template>

The <xsl:apply-templates> instruction will cause other elements than xs:element to be processed. <xsl:apply-templates>指令将导致处理除xs:element之外的其他元素。 For all such elements the following template is selected for processing: 对于所有这些元素,选择以下模板进行处理:

<xsl:template match="*" >     

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

</xsl:template>  

and this closes the loop and causes the endless recursion. 这会关闭循环并导致无限递归。

This problem can be avoided in the following way: 可以通过以下方式避免此问题

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

No other special templates are necessary -- just add the templates that process specific xsd elements. 不需要其他特殊模板 - 只需添加处理特定xsd元素的模板即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM