XSLT сортировка по имени тега и значению атрибута - PullRequest
4 голосов
/ 11 мая 2011

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

<a>
    <b attribute="e"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

И ожидаемый результат:

<a>
    <b attribute="b"></b>
    <b attribute="e"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Вот моя попытка решить эту проблему:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*">
                <xsl:sort select="."/>
            </xsl:apply-templates>

            <xsl:apply-templates select="node()">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

И это, очевидно,вообще не работает ...

В приведенном выше примере я хочу отсортировать тег b по значению их атрибута, но, как вы можете видеть, тег d не сортируется по значению атрибута, потому что это другое имя тега ...

Интересно, возможно ли это с помощью XSLT ... У вас есть идея?

Заранее спасибо.

ОБНОВЛЕНИЕ ----------------------

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

Допустим, у меня есть этот XML:

<a>
    <b attribute="e" optionalAttr="fg"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

Я добавил необязательный параметр для b тег.При применении решения andyb необязательный параметр будет игнорироваться, поскольку он не соответствует шаблону.Вот результат:

<a>
    <b attribute="b"></b>
    <b attribute="e"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Вместо следующего я ожидаю:

<a>
    <b attribute="b"></b>
    <b attribute="e" optionalAttr="fg"></b>
    <c></c>
    <d attribute="a"></d>
</a>

У вас есть идеи?Заранее спасибо.

Ответы [ 3 ]

7 голосов
/ 11 мая 2011

Это преобразование XSLT 2.0 выполняет сортировку по имени элемента и нескольким атрибутам nameand value :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:sort select="name()" />
                <xsl:sort select="my:attributeScore(.)" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="my:attributeScore" as="xs:string">
      <xsl:param name="pThis" as="node()"/>

      <xsl:variable name="vScore">
          <xsl:for-each select="$pThis/@*">
           <xsl:sort select="name()"/>

           <xsl:value-of select="concat(name(),'+',.)"/>
          </xsl:for-each>
          <xsl:text>|</xsl:text>
      </xsl:variable>

      <xsl:sequence select="string-join($vScore, '')"/>
    </xsl:function>
</xsl:stylesheet>

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

<a>
    <b attribute="e" x="y"></b>
    <b attribute="e" x="x"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

получается правильно отсортированный результат :

<a>
   <b attribute="b"/>
   <b attribute="e" x="x"/>
   <b attribute="e" x="y"/>
   <c/>
   <d attribute="a"/>
</a>
7 голосов
/ 11 мая 2011

Вы можете использовать несколько xsl:sort инструкций, например:

<xsl:template match="node()|@*">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*">
      <xsl:sort select="name()" />
      <xsl:sort select="@*" />
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

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

Редактировать

Это странно, потому что для следующего XML:

<a>
    <b attribute="e" optionalAttr="fg"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

и XSL выше, я получаю этот результат:

<a>
    <b attribute="b"></b>
    <b attribute="e" optionalAttr="fg"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Сюда входит требуемый необязательный атрибут, но порядок отличается от XML в редактируемом вопросе (<c></c> находится в другой позиции).

1 голос
/ 12 марта 2013

Я только что увидел этот вопрос, и, поскольку я новичок в xpath и XSL, решил, что попробую.

Кажется, я пришел к совершенно другому решению.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
    <xsl:copy>
        <xsl:apply-templates select="* | @*">
            <xsl:sort select="not(@*)" order="ascending" data-type="number"/>
            <xsl:sort select="@*"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>
<xsl:template match="*/@*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="text()[not(string-length(normalize-space()))]"/>
<xsl:template match="*/text()[normalize-space()]">
    <xsl:value-of select="normalize-space()"/>
</xsl:template>

Это зависит от того, как вы хотите, чтобы атрибуты были в порядке ...

Образец 1:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b attribute="e" ></b>
    <b attribute="b" ></b>
    <c></c>
    <d attribute="a"></d>
</a>

Результат 1

<a>
  <d attribute="a" />
  <b attribute="b" />
  <b attribute="e" />
  <c />
</a>

Образец 2

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b attribute="e" ></b>
    <b attribute="b" optionalAttr="fg"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Результат 2

<?xml version="1.0" encoding="utf-8"?>
<a>
  <d attribute="a" />
  <b attribute="b" optionalAttr="fg" />
  <b attribute="e" />
  <c />
</a>

Просто интересно, может ли кто-нибудь увидеть что-то не так с этим подходом?

Спасибо заранее

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