Преобразование xml в xml с использованием проблемы иерархии в кодировке xslt xslt v1 - PullRequest
3 голосов
/ 21 декабря 2010

В моем входном XML-файле у меня есть закодированная иерархия в атрибуте элементов "lp":

<element lp="1"/>
<element lp="1.1"/>
<element lp="2"/>
<element lp="3"/>
<element lp="3.1" />
<element lp="3.2" />
<element lp="3.2.1" />

Как преобразовать эти данные XML в

<element lp="1">
   <element lp="1.1"/>
</element>
<element lp="2"/>
<element lp="3">
   <element lp="3.1"/>
   <element lp="3.2">
      <element lp="3.2.1">
   </element>
</element>

Ответы [ 2 ]

3 голосов
/ 21 декабря 2010

Я думаю, это был ответ раньше ... Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="root">
        <result>
            <xsl:apply-templates select="element[not(contains(@lp,'.'))]"/>
        </result>
    </xsl:template>
    <xsl:template match="element">
    <xsl:variable name="vLevel" select="concat(@lp,'.')"/>
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates
                 select="../element[starts-with(@lp,$vLevel)]
                                   [not(contains(substring-after(@lp,$vLevel),
                                                 '.'))]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<result>
    <element lp="1">
        <element lp="1.1"></element>
    </element>
    <element lp="2"></element>
    <element lp="3">
        <element lp="3.1"></element>
        <element lp="3.2">
            <element lp="3.2.1"></element>
        </element>
    </element>
</result>
3 голосов
/ 21 декабря 2010

Вероятно, существует простой способ сделать это с помощью XSLT2.0, но я предположил, что здесь XSLT1.0.

Единственное, что не нужно делать, это то, что ваш XML не является строго допустимым, поскольку в нем отсутствует кореньэлемент.Для целей ответа я предположил, что корневой элемент называется elements

. Для этого, я думаю, вам нужна функция для определения «уровня» элемента.Это можно сделать, посчитав количество полных остановок в атрибуте @lp.В XSLT1.0 я сделал это, удалив из текста все точки остановки и сравнив длину полученной строки с длиной исходной строки

<xsl:variable name="level" select="string-length(@lp) - string-length(translate(@lp, '.', ''))" />

Таким образом, чтобы соответствовать элементам верхнего уровня, вы бы это сделали...

<xsl:apply-templates 
   select="element[string-length(@lp) - string-length(translate(@lp, '.', '')) = 0]"/>

Это будет соответствовать следующим элементам

<element lp="1."/>
<element lp="2."/>
<element lp="3."/>

Далее, для каждого соответствующего элемента это случай соответствия следующих элементов, где

  • Атрибут @lp начинается с текущего атрибута @lp
  • Уровень на один больше, чем текущий уровень

Это можно сделать с помощью следующего выбора

<xsl:apply-templates 
   select="following-sibling::element[substring(@lp, 1, $len) = $lp][string-length(@lp) - string-length(translate(@lp, '.', '')) = $level + 1]"/>

(Примечание: $ len и $ level - это переменные, содержащие длину текущего атрибута @lp и текущий уровень)

Если задать это значение в целом, получится следующий XSLT ....

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:template match="/elements">
      <elements>
         <xsl:apply-templates select="element[string-length(@lp) - string-length(translate(@lp, '.', '')) = 0]"/>
      </elements>
   </xsl:template>

   <xsl:template match="element">
      <xsl:variable name="lp" select="@lp"/>
      <xsl:variable name="len" select="string-length(@lp)"/>
      <xsl:variable name="level" select="$len - string-length(translate(@lp, '.', ''))" />

      <xsl:copy>
         <xsl:copy-of select="@lp"/>
         <xsl:apply-templates select="following-sibling::element[substring(@lp, 1, $len) = $lp][string-length(@lp) - string-length(translate(@lp, '.', '')) = $level + 1]"/>
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

При применении к следующему XML

<elements>
    <element lp="1"/>
    <element lp="1.1"/>
    <element lp="2"/>
    <element lp="3"/>
    <element lp="3.1"/>
    <element lp="3.2"/>
    <element lp="3.2.1"/>
</elements>

Создает следующий вывод

<elements>
    <element lp="1">
        <element lp="1.1"/>
    </element>
    <element lp="2"/>
    <element lp="3">
        <element lp="3.1"/>
        <element lp="3.2">
            <element lp="3.2.1"/>
        </element>
    </element>
</elements>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...