2010-07-21 3 views
1

Я попытался выполнить XSLT-преобразование XSD-файла. Моя цель состоит в том, чтобы создать SQL из XSD. До сих пор так хорошо, это то, что у меня есть:XSLT transform создает 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:?

EDIT: Исходный код был из here и это уже была ошибка. Я попытался исправить это, упростив XSLT до тех пор, пока не останется только ошибка.

+0

Какова ваша таблица стилей? Выбранный образец не имеет никакого смысла, поскольку он ничего не выводит. Это в основном рекурсивный «вызов» для одного и того же шаблона, что приводит к созданию SOE. –

+0

см. Мои правки в конце моего вопроса – codymanix

ответ

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> 

С помощью этой таблицы стилей нужно добавить шаблоны с парами schema были ваша расширена схема. Кроме того, вам необходимо применить шаблоны с параметром schema как select="$schema".

EDIT: Извините, небольшая ошибка. Кроме того, объяснение: при обработке модульной схемы вам нужно сначала получить полную расширенную схему, потому что иначе вы в конечном итоге вызываете шаблон рекурсии для получения ссылок и определений типов в разных схемах каждый раз. С моим шаблоном вы получаете полную расширенную схему в параметре $schema, поэтому при обработке xs:element с помощью @type="someType" вы можете продолжить процесс с xsl:apply-templates select="$schema[self::xs:complexType[@name='someType']]".

0

Проблема, которая приводит к бесконечной рекурсии здесь:

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

    <xsl:apply-templates /> 

</xsl:template> 

<xsl:apply-templates> инструкция будет вызывать другие элементы, чем хз: элемент должен быть обработан. Для всех таких элементов выбирается следующий шаблон для обработки:

<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

ваш ответ - лучшее объяснение рекурсии. Но он не охватывает часть «Получить узлы схемы из этой схемы и любые включенные схемы». – 2010-07-21 20:28:57

+0

@Alejandro: Спасибо, я думаю, что исправил это сейчас. –