XSL не может найти решение для моего преобразования данных - PullRequest
1 голос
/ 02 ноября 2009

У меня есть XML, который выглядит так:

<ROW ref="0005631" type="04" line="1" value="Australia"/>
<ROW ref="0005631" type="00" line="1" value="John"/>
<ROW ref="0005631" type="02" line="1" value="Builder"/>
<ROW ref="0005631" type="01" line="1" value="Smith"/>

Мне нужно решение в XSL, чтобы отформатировать его так:

John Smith Builder Australia

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

Ответы [ 3 ]

2 голосов
/ 02 ноября 2009

Чтобы использовать xsl:sort для ваших данных, у вас должен быть родительский узел, который вы не предоставили в своем примере кода, но он должен быть у вас, чтобы ваш XML-документ был действительным. Предполагая, что родительский узел равен <TABLE />, ваш ввод будет.

<TABLE>
    <ROW ref="0005631" type="04" line="1" value="Australia"/>
    <ROW ref="0005631" type="00" line="1" value="John"/>
    <ROW ref="0005631" type="02" line="1" value="Builder"/>
    <ROW ref="0005631" type="01" line="1" value="Smith"/>
</TABLE>

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

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="TABLE">
    <xsl:apply-templates>
      <xsl:sort select="@type" data-type="number"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="ROW">
    <xsl:apply-templates select="@value"/>
    <xsl:text>&#x20;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

Если вы хотите отсортировать на основе ref, type, line вместо простого type, вы можете использовать следующее для шаблона TABLE.

  <xsl:template match="TABLE">
    <xsl:apply-templates>
      <xsl:sort select="@ref" data-type="number"/>
      <xsl:sort select="@type" data-type="number"/>
      <xsl:sort select="@line" data-type="number"/>
    </xsl:apply-templates>
  </xsl:template>

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

0 голосов
/ 02 ноября 2009

В XSLT 1.0:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="text" encoding="utf-8" />

  <!-- index ROWs by their @ref -->
  <xsl:key name="kRowByRef"        match="ROW" use="@ref" />
  <!-- index ROWs by their @ref and @line -->
  <xsl:key name="kRowByRefAndLine" match="ROW" use="concat(@ref, ',', @line)" />

  <xsl:template match="/*">
    <!-- 1) rows are processed with "ORDER BY @ref" -->
    <xsl:apply-templates select="ROW" mode="ref-group">
      <xsl:sort select="@ref"  data-type="number" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="ROW" mode="ref-group">
    <!-- 2) rows are grouped by @ref -->
    <xsl:variable name="thisGroup" select="
      key('kRowByRef', @ref)
    " />

    <xsl:if test="generate-id() = generate-id($thisGroup[1])">
      <!-- 2.1) for the first item in the group, 
                nodes are processed with "ORDER BY @line" -->
      <xsl:apply-templates select="$thisGroup" mode="line-group">
        <xsl:sort select="@line" data-type="number" />
      </xsl:apply-templates>
      <!-- use a line as record separator -->
      <xsl:text>----------------------------&#10;</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="ROW" mode="line-group">
    <!-- 3) rows are grouped by @ref, @line -->
    <xsl:variable name="thisGroup" select="
      key('kRowByRefAndLine', concat(@ref, ',', @line))
    " />

    <xsl:if test="generate-id() = generate-id($thisGroup[1])">
      <!-- 3.1) for the first item in the group, 
                nodes are processed with "ORDER BY @type" -->
      <xsl:apply-templates select="$thisGroup" mode="line">
        <xsl:sort select="@type" data-type="number" />
      </xsl:apply-templates>
    </xsl:if>
  </xsl:template>

  <xsl:template match="ROW" mode="line">
    <!-- 4) rows are printed out & appended with space or newline -->
    <xsl:value-of select="@value" />
    <xsl:choose>
      <xsl:when test="position() = last()">
        <xsl:text>&#10;</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text> </xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Для этого совершенно неупорядоченного ввода:

<data>
  <ROW ref="0005631" type="04" line="1" value="Australia"/>
  <ROW ref="0005632" type="00" line="1" value="Jack"/>
  <ROW ref="0005631" type="00" line="1" value="John"/>
  <ROW ref="0005631" type="01" line="1" value="Smith"/>
  <ROW ref="0005632" type="04" line="2" value="Whiskey"/>
  <ROW ref="0005632" type="02" line="1" value="Tennessee"/>
  <ROW ref="0005631" type="02" line="1" value="Builder"/>
  <ROW ref="0005632" type="01" line="1" value="Daniel's"/>
</data>

Я получаю:

John Smith Builder Australia
----------------------------
Jack Daniel's Tennessee
Whiskey
----------------------------

Объяснение

Здесь происходит поэтапная группировка и сортировка, поэтому конечный результат группируется и упорядочивается по @ref, @line и @type.

Вся группировка мюнхенская. Шаблон # 1 обрабатывает все элементы <ROW> в @ref порядке:

<ROW ref="0005631" type="04" line="1" value="Australia"/>
<ROW ref="0005631" type="00" line="1" value="John"/>
<ROW ref="0005631" type="01" line="1" value="Smith"/>
<ROW ref="0005631" type="02" line="1" value="Builder"/>
<ROW ref="0005632" type="00" line="1" value="Jack"/>
<ROW ref="0005632" type="04" line="2" value="Whiskey"/>
<ROW ref="0005632" type="02" line="1" value="Tennessee"/>
<ROW ref="0005632" type="01" line="1" value="Daniel's"/>

Шаблон # 2 обрабатывает только первую из каждой @ref группы:

<ROW ref="0005631" type="04" line="1" value="Australia"/>
<ROW ref="0005632" type="00" line="1" value="Jack"/>

Передача всей группы ($thisGroup) шаблону № 3 в два этапа, в порядке @line:

<ROW ref="0005631" type="04" line="1" value="Australia"/>
<ROW ref="0005631" type="00" line="1" value="John"/>
<ROW ref="0005631" type="01" line="1" value="Smith"/>
<ROW ref="0005631" type="02" line="1" value="Builder"/>

<ROW ref="0005632" type="00" line="1" value="Jack"/>
<ROW ref="0005632" type="02" line="1" value="Tennessee"/>
<ROW ref="0005632" type="01" line="1" value="Daniel's"/>
<ROW ref="0005632" type="04" line="2" value="Whiskey"/>

Шаблон № 3 занимает первое место в каждой группе @line:

<ROW ref="0005631" type="04" line="1" value="Australia"/>
<ROW ref="0005632" type="00" line="1" value="Jack"/>
<ROW ref="0005632" type="04" line="2" value="Whiskey"/>

и обрабатывает их, передавая всю группу шаблону № 4 в три этапа, в @type порядке:

<ROW ref="0005631" type="00" line="1" value="John"/>
<ROW ref="0005631" type="01" line="1" value="Smith"/>
<ROW ref="0005631" type="02" line="1" value="Builder"/>
<ROW ref="0005631" type="04" line="1" value="Australia"/>

<ROW ref="0005632" type="00" line="1" value="Jack"/>
<ROW ref="0005632" type="01" line="1" value="Daniel's"/>
<ROW ref="0005632" type="02" line="1" value="Tennessee"/>

<ROW ref="0005632" type="04" line="2" value="Whiskey"/>

Шаблон # 4 печатает их, добавляя пробелы или переводы строк, где это необходимо.

0 голосов
/ 02 ноября 2009

Вы имели в виду, что хотите получить элементы из одной строки, а затем отобразить их в соответствии с номером типа? Я думаю xsl:sort это то, что вам нужно

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