2015-08-26 3 views
1

Запустите немного проблемы.CSV-текст, выводимый из преобразования XSLT, искажается при открытии в стороннем приложении

Я использую VS2015 для создания XSLT, который будет использоваться в сторонней программе. Я создал образцы данных из сторонней программы (Epicor Service Connect) в XML и на основе этого построил XSLT. Теперь, когда я отлаживаю таблицу стилей в VS, у меня есть ожидаемый результат - столбцы вверху, разделенные полуколониями, а затем каждый блок данных находится под ним, как и ожидалось.

Однако, когда я запускаю его через программу Service Connect, я получаю эту полную тайну:

Weird symbols rather than data

Мне нужно, чтобы иметь возможность вернуть свои данные в CSV, используя точку с запятой это в качестве разделителей. Надрез данных я получаю в VS показывает, что это работает:

Working data

И, конечно же, если положить в CSV, он показывает правильную информацию.

XSLT для всех, кто интересуется (обратите внимание, что это мой второй день использования XSLT, до этого я знал только, для чего это аббревиатура - так что это не фантастика), но если у вас есть предложения по улучшению, я с радостью принимаю конструктивная критика):

<xsl:stylesheet version="1.0" xmlns:csv="csv:csv" xmlns:message="http://Epicor.com/Message/2.0" 
                  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                  xmlns:ext_UserSchema="http://Epicor.com/SC/UserSchema"> 
<xsl:output method="text" encoding="utf-8" /> 
<xsl:strip-space elements="*" /> 

<xsl:template match="message:Receiver"/> 

<xsl:template match="message:Body"> 
    <xsl:apply-templates select="message:Req"/> 
</xsl:template> 

<xsl:template match="message:Req"> 
    <xsl:apply-templates select="message:Dta"/> 
</xsl:template> 

<xsl:template match="message:Dta"> 
    <xsl:call-template name="PrimaryDataLoadForESC"/> 
</xsl:template> 

<xsl:template match="*"> 
    <xsl:variable name="tessst" select="local-name()"/> 
    <xsl:choose> 
     <xsl:when test="$tessst = 'QueryResultDataSet'"> 
      <xsl:call-template name="PrimaryDataLoadNotESC"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:apply-templates select="message:Body"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="PrimaryDataLoadNotESC"> 
    <xsl:apply-templates select="/QueryResultDataSet/Results[1]/*" mode="header"/> 
    <xsl:apply-templates select="/QueryResultDataSet/Results" /> 
</xsl:template> 

<xsl:template name="PrimaryDataLoadForESC"> 
    <xsl:apply-templates select="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results[1]/*" mode="header"/> 
    <xsl:apply-templates select="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results" /> 
</xsl:template> 

<xsl:template match="*" mode="header"> 
    <xsl:value-of select="translate(local-name(), '_', ' ')"/> 
    <xsl:choose> 
     <xsl:when test="position()=last()"> 
      <xsl:text>&#xD;</xsl:text> 
     </xsl:when> 
     <xsl:otherwise>;</xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template match="QueryResultDataSet/Results"> 
    <xsl:apply-templates select="*" mode="dataNodes"/> 
</xsl:template> 

<xsl:template match="ext_UserSchema:QueryResultDataSet/ext_UserSchema:Results"> 
    <xsl:apply-templates select="*" mode="dataNodes"/> 
</xsl:template> 

<xsl:template match="*" mode="dataNodes"> 
    <xsl:value-of select="."/> 
    <xsl:choose> 
     <xsl:when test="position()=last()"> 
      <xsl:text>&#xD;</xsl:text> 
     </xsl:when> 
     <xsl:otherwise>;</xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 

Некоторые образцы данных:

Перед Service Connect (после отформатирован):

<QueryResultDataSet> 
<Results> 
    <Source_-_System>SOURCE SYSTEM 1</Source_-_System> 
    <Customer>96247</Customer> 
    <Description_-_Short>COMPANY DESCRIPTION SHORT</Description_-_Short> 
    <Description_-_Medium>COMPANY DESCRIPTION MEDIUM</Description_-_Medium> 
    <Description_-_Long>COMPANY DESCRIPTION LONG</Description_-_Long> 
</Results> 

После Service Connect:

<?xml version="1.0" encoding="utf-16"?> 
<msg:Msg xsi:schemaLocation="http://Epicor.com/Message/2.0 http://scshost/schemas/epicor/ScalaMessage.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:msg="http://Epicor.com/Message/2.0"> 
<msg:Hdr> 
    <msg:Ctrl> 
     <msg:MsgID></msg:MsgID> 
    </msg:Ctrl> 
    <msg:Sender> 
     <msg:Name></msg:Name> 
     <msg:Subname></msg:Subname> 
    </msg:Sender> 
    <msg:Logon></msg:Logon> 
</msg:Hdr> 
<msg:Body> 
    <msg:Req msg-type="DocumentToProcess" action="MapAndProcess"> 
     <msg:Dta> 
      <ext_UserSchema:QueryResultDataSet xmlns:msg="http://Epicor.com/InternalMessage/1.1" xmlns:ext_UserSchema="http://Epicor.com/SC/UserSchema"> 
       <ext_UserSchema:Results> 
        <ext_UserSchema:Source_System>SOURCE_SYS1</ext_UserSchema:Source_System> 
        <ext_UserSchema:Vendor>96247</ext_UserSchema:Vendor> 
        <ext_UserSchema:Description_-_Short>COMPANY DESCRIPTION SHORT</ext_UserSchema:Description_-_Short> 
        <ext_UserSchema:Description_-_Medium>COMPANY DESCRIPTION MEDIUM</ext_UserSchema:Description_-_Medium> 
        <ext_UserSchema:Description_-_Long>COMPANY DESCRIPTION LONG</ext_UserSchema:Description_-_Long> 
       </ext_UserSchema:Results> 
      </ext_UserSchema:QueryResultDataSet> 
     </msg:Dta> 
    </msg:Req> 
</msg:Body> 
</msg:Msg> 

Кто там есть какие-либо идеи относительно того, что может быть причиной этой проблемы?

+1

Я мог бы помочь вам с XSLT, но для этого потребуется немного больше ввода: знаете ли вы, какое фактическое требуемое изменение в выходе должно заставить его работать с Service Connect? Или вы можете создать пример вручную, который будет работать с Service Connect, и тот, который явно не работает? Кроме того, очень желательно использовать пример XML с минимальными входными данными. – Abel

+1

Кстати, со скриншота, я предполагаю, что есть проблема с кодировкой. То есть таблица стилей создаст UTF-8, но, учитывая, что вы создаете CSV, ожидаемый формат для Service Connect может быть ISO-8859-1 или попробовать даже US-ASCII в качестве последнего средства (вы можете установить это в 'xsl: output'). И вы уверены, что CSV должен быть разделен на ';'? Типичный CSV имеет значение ',' (значение C для запятой, а не точки с запятой;). – Abel

+0

Привет @Abel, спасибо, что вернулись ко мне. Мы требуем, чтобы заголовки имели символы подчеркивания (_), разделенные и замененные пробелами() для выходных столбцов CSV. Я отредактирую вопрос и предоставил два набора данных, которые я использую, чтобы достичь результата выше. Я дам кодировку выстрела - это хороший момент, вполне может и действительно быть. Что касается CSV, разделяемого точкой с запятой, мы сделали формат языка по умолчанию для точки с запятой, как разделитель, поскольку значения могут содержать запятые, но не точки с запятой. – DeeKayy90

ответ

2

Я удивлен, что я не заметил этого раньше:

Ваш рендеринг идет не так, из-за byte order mark! Первым символом является рендеринг в ISO-8859-1, CP1252 (windows) или Unicode 0xFF 'ÿ' и второй 0xFE 'þ', которые являются первым и вторым байтами в байтовом порядке при использовании UTF-16 (порядок в зависимости от сущности) или при использовании UTF-8 и вы применяете декодирование UTF-8 (байты равны 0xEF, 0xBB 0xBF).

Так, короче говоря, решить эту проблему, измените xsl:output содержать:

<xsl:output byte-order-mark="no" /> 

Но это будет работать только с XSLT 2.0 или выше. Если вы не можете переключиться на XSLT 2.0, вы должны проверить документацию своего процессора, если она поддерживает кодировку UTF-8 без байта-байта.

По крайней мере, в какой-то момент, the Saxon processor output a byte order mark при использовании текстового вывода с UTF-8. Кроме того, в Windows, Блокнот и многие другие редакторы автоматически выделяют знак байтового байта при сохранении файла (если вы после редактирования своего CSV вручную, это может произойти, например).

Чтобы решить эту проблему либо:

  • Переключение в XSLT 2.0 с любой, какой процессор
  • пост-процесс ваш выход удалить метку порядка байтов
  • Проверьте документацию вашего программного обеспечения сторонних производителей, если он имеет возможность удалить или игнорировать метку порядка байт
  • использовать другое кодирование, который не выводит отметку порядка байт
+0

Хорошие предложения, плюс один. –

+0

Извините @Abel, я был вдали от работы в течение последних нескольких дней. Я попробую это сейчас и вернусь к вам :) Спасибо за вашу помощь! – DeeKayy90

+1

Работал сон. Большое спасибо за вашу помощь Абель! :) – DeeKayy90