Таблица стилей XSLT: объединение элементов в один - PullRequest
2 голосов
/ 22 сентября 2010

Что такое таблица стилей XSLT 2.0, которая преобразует

<paramList>
    <param name="y" out="true"/>
    <param name="y" in="true"/>
    <param name="z" out="true"/>
    <param name="x" in="true"/>
</paramList>

в

<paramList>
    <param name="x" in="true" />
    <param name="y" in="true" out="true"/>
    <param name="z" out="true"/>
</paramList>

В результате параметры «in, only» предшествуют параметрам «in & out», которые, в свою очередь, предшествуют параметрам «out, only». Кроме того, два элемента "y" были объединены в один.

Ответы [ 4 ]

0 голосов
/ 27 сентября 2010

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

Вот пример ввода:

<root>
  <func name="one">
    <paramList>
      <param name="y" out="true"/>
      <param name="y" in="true"/>
      <param name="z" out="true"/>
      <param name="x" in="true"/>
    </paramList>
  </func>

  <func name="two">
    <paramList>
      <param name="z" in="true"/>
    </paramList>
  </func>
</root>

Вотмоя предложенная таблица стилей, построенная на ответе Obalix.Хитрость заключается в том, чтобы использовать идентификатор локального ключа, содержащий идентификатор элемента paramList.

<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:key name="paramsByName" match="param" use="concat(generate-id(..), '/', @name)"/>
  <xsl:template match="paramList">
    <xsl:copy>
       <xsl:variable name="id" select="generate-id(.)"/>
       <xsl:for-each select="param[count(. | key('paramsByName', concat($id, '/', @name))[1]) = 1]">
         <xsl:copy>
           <xsl:copy-of select="key('paramsByName', concat($id, '/', @name))/@*"/>
         </xsl:copy>
       </xsl:for-each>
     </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
0 голосов
/ 22 сентября 2010

На всякий случай, если кому-то нужно сделать это в XSLT 1:

<?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:key name="paramsByName" match="param" use="@name"/>
    <xsl:template match="/paramList">
        <xsl:copy>
            <xsl:for-each select="param[count(. | key('paramsByName', @name)[1]) = 1]">
            <xsl:sort select="@name"/>
            <xsl:copy>
                <xsl:for-each select="key('paramsByName', @name)">
                <xsl:copy-of select="@*"/>
            </xsl:for-each>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

При этом используется группировка Munchian , поскольку XSLT 1 не имеет конструкции группировки.

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

Очевидно, что также возможно просто скопировать атрибуты in и out, в этом случае следующая таблица стилей выполняет свою работу (также следуя советам Dimetre:

<?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:key name="paramsByName" match="param" use="@name"/>
    <xsl:template match="/paramList">
        <xsl:copy>
            <xsl:for-each select="param[count(. | key('paramsByName', @name)[1]) = 1]">
            <xsl:sort select="@name"/>
            <xsl:copy-of select="key('paramsByName', @name)/@*[local-name() = 'in' or local-name() = 'out']"/>
        </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
0 голосов
/ 22 сентября 2010

Небольшое улучшение:

В решениях @ Nick-Jones и @Obalix короче написать :

<xsl:copy-of select="current-group()/@*"/>

или

<xsl:copy-of select="key('paramsByName', @name)/@*"/>

чем соответственно :

<xsl:for-each select="current-group()/@*">   
  <xsl:copy/>   
</xsl:for-each>   

или

<xsl:for-each select="key('paramsByName', @name)">     
 <xsl:copy-of select="@*"/>     
</xsl:for-each>     
0 голосов
/ 22 сентября 2010
<?xml version="1.0" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/paramList">
  <xsl:copy>
    <xsl:for-each-group select="param" group-by="@name">
      <xsl:sort select="current-group()/@in" order="descending"/>
      <xsl:sort select="current-group()/@out"/>
      <param name="{current-grouping-key()}">
        <xsl:for-each select="current-group()/@*">
          <xsl:copy/>
        </xsl:for-each>
      </param>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

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