XSLT-преобразование создает исключение StackoverflowException - PullRequest
1 голос
/ 21 июля 2010

Я попытался выполнить XSLT-преобразование XSD-файла. Моя цель в конце концов создать SQL из XSD. Пока все хорошо, вот что у меня есть:

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: element?

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

Ответы [ 3 ]

4 голосов
/ 21 июля 2010

линия

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

отправляет текущий узел (xs: element) в шаблон, с которого он был запущен. Затем он совпадает с ним в цикле for и отправляет себя снова. Переполнение стека неизбежно.

0 голосов
/ 21 июля 2010

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

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

    <xsl:apply-templates />  

</xsl:template>

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

<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 голосов
/ 21 июля 2010

Поскольку у Вуди есть ответ, у вас есть круговой вызов («Для каждого элемента ... применять шаблоны для элементов»).Итак, правильный путь:

<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']]".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...