Как отсортировать элементы (столбцы) в xslt для преобразования файла xml в формат csv - PullRequest
2 голосов
/ 25 сентября 2011
<?xml version="1.0" encoding="utf-8"?>
<Report p1:schemaLocation="Customer details  http://reportserver?%2fCustomer details&amp;rs%3aFormat=XML&amp;rc%3aSchema=True" Name="Customer details" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance" xmlns="Customer details">
  <table2>
   <Detail_Collection>
         <Detail Col1="aaa" col1_SeqID="2"  col1_Include="1"
                 Col2="aaa" col2_SeqID="1"  col2_Include="1"
                 Col3="aaa" col3_SeqID=""  col3_Include="0"
                 Col4="aaa" col4_SeqID="4"  col4_Include="1"
                 Col5="aaa" col5_SeqID=""  col5_Include="0"
                 ... ... ...
                 ... ... ...
                 ... ... ...
                 Col50="aaa" col50_SeqID="3"  col50_Include="1"
                 />
   <Detail_Collection>
</table2>
</Report>

Приведенный выше xml создается SSRS для файла RDL.Я хочу преобразовать вышеуказанный XML-файл в формат CSV, используя XSLT (настраиваемый формат).Файл RDL (отчет SSRS) очень прост с 50 столбцами и отображает данные для всех столбцов в зависимости от выбора пользователя в пользовательском интерфейсе.В пользовательском интерфейсе есть выбор параметров для всех 50 столбцов (т. Е. Они могут выбрать порядок столбцов, они могут выбрать конкретный столбец, который будет включен в отчет или нет, стиль шрифта и т. Д.).Как уже упоминалось, каждый столбец имеет 2 основных функции, т.е. они могут быть отсортированы и упорядочены по выбранным параметрам.

Например, из выходных данных отчета, т.е. в указанном выше формате xml, вы увидите все 50 столбцовсуществуют в формате xml, но я также включаю дополнительные файлы, которые обычно скрываются в отчете.

Col1 включен в отчет и упорядочен (seqID) как 2-й столбец в файле csv.Col2 также включен в отчет и упорядочен как первый столбец в файле csv.Col3 не включен в отчет, и выбор заказа пуст, поэтому он не включен в файл CSV.... ... подобно тому, что col50 включен в отчет, но упорядочен как 3-й столбец в файле csv.

Моя главная задача здесь - создать файл xslt для "CSV" и поместить столбцыв порядке выбора, который выбирается для каждого пользователя.

Вывод в файл CSV после преобразования будет выглядеть следующим образом:

Col2    Col1    Col50   Col4
 ...  ...       ...     ....

Любую хорошую идею для созданияЭтот вид xsl-файла высоко ценится, и я благодарю вас за понимание моего вопроса и за попытку помочь мне в этом отношении.

1 Ответ

1 голос
/ 25 сентября 2011

I. Это XSLT 1.0 преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:c="Customer details">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="c:Detail">
     <xsl:apply-templates select=
      "@*[substring(name(), string-length(name())-5)
         = '_SeqID'
        and
          number(.) = number(.)
          ]
     ">
      <xsl:sort data-type="number"/>
     </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:if test="not(position()=1)">,</xsl:if>
  <xsl:value-of select=
    "../@*
       [name()
       =
        concat('Col',substring-before(substring(name(current()),4),'_'))
        ]"/>
 </xsl:template>
</xsl:stylesheet>

при применении к этому XML-документу (предоставлен, сделан правильно и однозначно):

<Report
p1:schemaLocation="Customer details  http://reportserver?%2fCustomer details&amp;rs%3aFormat=XML&amp;rc%3aSchema=True"
Name="Customer details"
xmlns:p1="http://www.w3.org/2001/XMLSchema-instance"
xmlns="Customer details">
    <table2>
        <Detail_Collection>
            <Detail Col1="aaa1" col1_SeqID="2"  col1_Include="1"
            Col2="aaa2" col2_SeqID="1"  col2_Include="1"
            Col3="aaa3" col3_SeqID=""  col3_Include="0"
            Col4="aaa4" col4_SeqID="4"  col4_Include="1"
            Col5="aaa5" col5_SeqID=""  col5_Include="0"
            Col50="aaa50" col50_SeqID="3"  col50_Include="1"
            />
        </Detail_Collection>
    </table2>
</Report>

дает желаемый, правильный результат :

aaa2,aaa1,aaa50,aaa4

Объяснение

  1. Мы используем это выражение XPath 1.0:

__

substring($s1, string-length($s1) - string-length($s2) +1) = $s2

эквивалентно выражению XPath 2.0:

ends-with($s1, $s2))

0,2. Надлежащее использование <xsl:sort>, substring(), name() и current().

0,3. Используя тот факт, что строка $s преобразуется в число тогда и только тогда, когда:

__

number($s) = number($s)

II. Решение XSLT 2.0 :

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:c="Customer details">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>    

 <xsl:template match="c:Detail">
         <xsl:apply-templates select=
          "@*[ends-with(name(),'_SeqID')
            and . castable as xs:integer]">
          <xsl:sort  select="xs:integer(.)"/>
         </xsl:apply-templates>
 </xsl:template>
 <xsl:template match="@*">
      <xsl:if test="not(position()=1)">,</xsl:if>
      <xsl:value-of select=
        "../@*
           [name()
           eq
            concat('Col',translate(name(current()),'col_SeqID',''))]"/>
 </xsl:template>
</xsl:stylesheet>

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

aaa2,aaa1,aaa50,aaa4

Обновление : @desi попросил также создать заголовок.

Вот обновленное преобразование XSLT 1.0 (как указано, @desi ограничено использованием только XSLT 1.0), которое делает это:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:c="Customer details">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="c:Detail">

     <xsl:for-each select=
      "@*[substring(name(), string-length(name())-5)
         = '_SeqID'
        and
          number(.) = number(.)
          ]
        ">
        <xsl:sort data-type="number"/>

       <xsl:value-of select=
       "concat('Col',
               substring-before(substring(name(current()),4),
                                '_')
               )
       "/>

          <xsl:text>&#9;</xsl:text>
     </xsl:for-each>
     <xsl:text>&#10;</xsl:text>

     <xsl:apply-templates select=
      "@*[substring(name(), string-length(name())-5)
         = '_SeqID'
        and
          number(.) = number(.)
          ]
     ">
      <xsl:sort data-type="number"/>
     </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:if test="not(position()=1)">,</xsl:if>
  <xsl:value-of select=
    "../@*
       [name()
       =
        concat('Col',substring-before(substring(name(current()),4),'_'))
        ]"/>
 </xsl:template>
</xsl:stylesheet>

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

Col2    Col1    Col50   Col4    
aaa2,aaa1,aaa50,aaa4
...