Недопустимый токен XSLT приводит к неверному документу XML - PullRequest
0 голосов
/ 08 ноября 2018

Я использую файл XSLT для преобразования файла XML в другой файл XML, а затем создаю этот файл XML локально. Я получаю эту ошибку:

System.InvalidOperationException: 'Текст маркера в состоянии Start приведет к неверному документу XML. Убедитесь, что для параметра ConformanceLevel установлено значение ConformanceLevel.Fragment или ConformanceLevel.Auto, если вы хотите записать фрагмент XML. «

Файл XSLT был отлажен в визуальных студиях, и похоже, что он работает правильно, но я не понимаю эту ошибку. Что это значит и как это можно исправить?

Это мой XML:

<?xml version="1.0" encoding="utf-8"?>
<In xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="take.xsd">
  <Submit ID="1234">
    <Values>
      <Code>34</Code>
      <Source>27</Source>
    </Values>
    <Information>
      <Number>55</Number>
      <Date>2018-05-20</Date>
      <IsFile>1</IsFile>
      <Location></Location>
      <Files>
        <File>
          <Name>Red.pdf</Name>
          <Type>COLOR</Type>
        </File>
        <File>
          <Name>picture.pdf</Name>
          <Type>IMAGE</Type>
        </File>        
      </Files>
    </Information>
  </Submit>
</In>

Мой XSLT-код:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

  <!-- identity template - copies all elements and its children and attributes -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/In">
    <!-- Remove the 'In' element -->
    <xsl:apply-templates select="node()"/>
  </xsl:template>

  <xsl:template match="Submit">
    <!-- Create the 'Q' element and its sub-elements -->
    <Q xmlns:tns="Q" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schema.xsd" Source="{Values/Source}" Notification="true">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="Values" />
        <xsl:apply-templates select="Information" />
        <xsl:apply-templates select="Information/Files" />
      </xsl:copy>
    </Q>
  </xsl:template>

  <xsl:template match="Information">
    <!-- Create the 'Data' sub-element without all of its children -->
    <xsl:copy>
      <xsl:copy-of select="Number"/>
      <xsl:copy-of select="Date"/>
      <xsl:copy-of select="IsFile"/>
      <xsl:copy-of select="Location"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

А это код C #, используемый для преобразования файла:

        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load(@"D:\\Main\XLSTFiles\Test.xslt");
        string xmlPath = @"D:\Documents\Test2.xml";
        using (XmlWriter w = XmlWriter.Create(@"D:\Documents\NewFile.xml"))
        {
            xslt.Transform(xmlPath, w);
        }

Кроме того, есть ли способ создать новый XML-файл с правильным отступом? Кажется, каждый узел создается после закрытия последнего, а в пользовательском шаблоне он просто добавляет каждый элемент один за другим.

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Чтобы расширить превосходный ответ Майкла Кея (поскольку это было слишком долго, чтобы писать в комментариях), для вашего конкретного входного XML проблема заключается в пробелах. В шаблоне соответствия /In вы делаете это ...

<xsl:template match="/In">
  <!-- Remove the 'In' element -->
  <xsl:apply-templates select="node()"/>
</xsl:template>

Но, выбрав node(), вы выбираете узлы пропусков до и после дочернего Submit, поэтому вы получаете текстовый узел перед корневым элементом Q, вызывающим ошибку.

Итак, что вы могли бы сделать в этом случае, это просто удалить пробел из вашего XML, добавив его в XSLT

<xsl:strip-space elements="*" />

В качестве альтернативы, вы также можете сделать это, чтобы выбрать только элементы, в отличие от других узлов (хотя это будет пропускать комментарии и инструкции по обработке)

<xsl:apply-templates select="*" />

Однако, если у вас есть несколько элементов Submit в вашем XML, вы затем получите несколько элементов Q в своем выводе, которые будут фрагментом, как и один корневой элемент. Если это то, что вы действительно намерены, то вы должны внести следующие изменения в ваш C # ...

 using (XmlWriter w = XmlWriter.Create(@"C:\Users\tcase.BGT\Documents\NewFile.xml", xslt.OutputSettings ))

По умолчанию ConformanceLevel - ConformanceLevel.Auto, который, я думаю, разрешает фрагменты. Добавление этого также решит вашу проблему с отступами, так как будет использовать настройки в xsl:output.

0 голосов
/ 08 ноября 2018

Это удивительно бесполезное сообщение, не так ли? Но я думаю, что смогу расшифровать это для вас.

Процессор XSLT выдает выходные данные, записывая события, такие как начальный документ, начальный элемент, выходной текст, в XML Writer.

Если вы хотите создать правильно сформированный XML-документ, у вас не может быть текста до начала первого элемента. В сообщении говорится, что если последнее, что вы сделали, это выпустили начальный документ, то следующим не может быть текст, потому что документ будет некорректно сформирован (он содержит недопустимый текст, но означает неправильный формат). .

Теперь таблицам стилей XSLT разрешено создавать «правильно сформированные фрагменты», а не только писать «правильно сформированные документы». На самом деле, термин, используемый в спецификации XML, - это «правильно сформированный внешний общий анализируемый объект», но это немного странно, поэтому все называют их «фрагментами», потому что именно так их называет DOM, и нет смысла использовать правильную терминологию в сообщения об ошибках, если никто не понимает этого. Разница в том, что фрагмент может содержать несколько элементов и текстовых узлов на верхнем уровне, например this <b>really</b> is a <i>well-formed</i> fragment. Проблема заключается в том, что место назначения, в которое вы записываете выходные данные XSLT, может не обрабатывать фрагменты, и в этом конкретном случае XML Writer может обрабатывать фрагмент, только если он настроен для этого.

Я подозреваю, что вы на самом деле не собирались создавать фрагмент, и вам нужно исправить свой XSLT-код, чтобы он выводил правильно сформированный документ.

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