[英]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.