Двухфазное преобразование с использованием XSLT 2.0 - PullRequest
1 голос
/ 24 апреля 2011

Я пытаюсь взять файл CSV в качестве входных данных и преобразовать его в XML. Я новичок в XSLT и нашел способ конвертировать CSV в XML (на примере Andrew Welch ) примерно так:

Входной файл CSV:

car manufacturer,model,color,price,inventory
subaru,outback,blue,23195,54
subaru,forester,silver,20495,23

И мой выходной XML будет:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
   <row>
      <column name="car manufacturer">subaru</column>
      <column name="model">outback</column>
      <column name="color">blue</column>
      <column name="price">23195</column>
      <column name="inventory">54</column>
   </row>
   <row>
      <column name="car manufacturer">subaru</column>
      <column name="model">forester</column>
      <column name="color">silver</column>
      <column name="price">20495</column>
      <column name="inventory">23</column>
   </row>
</rows>

Мой желаемый результат на самом деле похож на:

<stock>
   <model>
      <car>subaru outback</car>
      <color>blue</color>
      <price>23195</price>
      <inventory>54</inventory>
   </model>
   <model>
      <car>subaru forester</car>
      <color>silver</color>
      <price>20495</price>
      <inventory>23</inventory>
   </model>
</stock>

Что я прочитал, так это то, что лучше всего это сделать с помощью двухфазного преобразования. CSV в XML выполняется с использованием XSLT 2.0, поэтому я подумал, что двухфазное преобразование будет также выполнено с использованием этой функции без использования функции набора узлов.

Таким образом, первый этап заключается в том, чтобы принять исходный файл CSV в качестве входных данных, а затем вывести промежуточный XML, показанный выше. Затем возьмите этот промежуточный XML и передайте его в другое преобразование, чтобы получить желаемый результат.

Кто-нибудь может помочь с тем, как можно осуществить двухфазное преобразование? У меня проблемы с передачей выходных данных первой фазы как входных данных фазы 2?

У меня пока что-то вроде этого:

<xsl:import href="csv2xml.xsl"/>
<xsl:output method="xml" indent="yes" />

<xsl:variable name="intermediate">
    <xsl:apply-templates select="/" mode="csv2xml"/>
</xsl:variable>

<xsl:template match="rows" name="main">

 **[This is what I'm having trouble with]**

</xsl:template>

Ответы [ 3 ]

7 голосов
/ 25 апреля 2011

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

Однако, когда вам нужны две фазы, общая модельэто:

<xsl:template match="/">
  <xsl:variable name="phase-1-result">
    <xsl:apply-templates select="/" mode="phase-1"/>
  </xsl:variable>
  <xsl:apply-templates select="$phase-1-result" mode="phase-2"/>
</xsl:template>

с шаблонными правилами для фазы 1 и фазы 2 (и их вызовами apply-templates), которые все находятся в режиме фазы-1 или фазы-2 соответственно.

2 голосов
/ 12 марта 2012

Здесь вы можете найти пример того, как сделать это с XSLT 3.0:

http://www.stylusstudio.com/tutorials/intro-xslt-3.html

И см. В разделе «Манипуляции с текстом».

2 голосов
/ 25 апреля 2011

Эта таблица стилей XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:variable name="vLines"
         select="tokenize(unparsed-text('test.txt'),'(&#xD;)?&#xA;')"/>
        <xsl:variable name="vHeaders"
         select="tokenize($vLines[1],',')"/>
        <stock>
            <xsl:for-each select="$vLines[position()!=1]">
                <model>
                    <xsl:variable name="vColumns" select="tokenize(.,',')"/>
                    <xsl:for-each select="$vColumns">
                        <xsl:variable name="vPosition" select="position()"/>
                        <xsl:variable name="vHeader"
                         select="$vHeaders[$vPosition]"/>
                        <xsl:choose>
                            <xsl:when test="$vHeader = 'car manufacturer'">
                                <column name="car">
                                    <xsl:value-of
                                     select="(.,$vColumns[
                                                   index-of($vHeaders,'model')
                                                ])"/>
                                </column>
                            </xsl:when>
                            <xsl:when test="$vHeader = 'model'"/>
                            <xsl:otherwise>
                                <column name="{$vHeader}">
                                    <xsl:value-of select="."/>
                                </column>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </model>
            </xsl:for-each>
        </stock>
    </xsl:template>
</xsl:stylesheet>

Выход:

<stock>
    <model>
        <column name="car">subaru outback</column>
        <column name="color">blue</column>
        <column name="price">23195</column>
        <column name="inventory">54</column>
    </model>
    <model>
        <column name="car">subaru forester</column>
        <column name="color">silver</column>
        <column name="price">20495</column>
        <column name="inventory">23</column>
    </model>
</stock>

Примечание : в XSLT 3.0 вы сможете применять шаблоны к элементам в целом.

РЕДАКТИРОВАТЬ : правильные имена.

...