Нужно преобразование XSLT - PullRequest
0 голосов
/ 16 марта 2011

Привет, у меня есть дерево, похожее на структуру xml ... Я хочу преобразовать его, используя XSLT для вычисления productPrices ... если бы это была линейная структура, я мог бы использовать простую функцию суммы с фильтром по имени ... Нокак его древовидная структура, ему нужна какая-то рекурсивная трансформация ... Может кто-нибудь предложить мне какую-то технику или подход для этой трансформации ... Я пытаюсь написать это с моей стороны ... Было бы полезно, если бы вымогу предложить несколько подходов ...

<?xml version="1.0" encoding="UTF-8"?>
<Products>
    <Product>
        <Name>X2</Name>
        <Price>1</Price>
        <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
            </Product>
            <Product>
                <Name>X2</Name>
                <Price>1</Price>
            </Product>
        </Product>
        <Product>
            <Name>X2</Name>
            <Price>1</Price>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
            </Product>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <Product>
                    <Name>X2</Name>
                    <Price>1</Price>
                </Product>
            </Product>
        </Product>
    </Product>
    <Description>
        <text>dsd</text>
    </Description>
    <Description>
        <text>dsd</text>
    </Description>
</Products>

Конечная структура, которая мне нужна, должна быть.

<?xml version="1.0" encoding="UTF-8"?>
<Products>
    <Product>
        <Name>X2</Name>
        <Price>1</Price>
        <!--Total Price of X2 Products-->
        <TotalPrice>4</TotalPrice>
        <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <!--Total Price of X1 Products-->
            <TotalPrice>4</TotalPrice>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <!--Total Price of X1 Products-->
                <TotalPrice>4</TotalPrice>
            </Product>
            <Product>
                <Name>X2</Name>
                <Price>1</Price>
                <!--Total Price of X2 Products-->
                <TotalPrice>4</TotalPrice>
            </Product>
        </Product>
        <Product>
            <Name>X2</Name>
            <Price>1</Price>
            <!--Total Price of X2 Products-->
            <TotalPrice>4</TotalPrice>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <!--Total Price of X1 Products-->
                <TotalPrice>4</TotalPrice>
            </Product>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <!--Total Price of X1 Products-->
                <TotalPrice>4</TotalPrice>
                <Product>
                    <Name>X2</Name>
                    <Price>1</Price>
                    <!--Total Price of X2 Products-->
                    <TotalPrice>4</TotalPrice>
                </Product>
            </Product>
        </Product>
    </Product>
    <Description>
        <text>dsd</text>
    </Description>
    <Description>
        <text>dsd</text>
    </Description>
</Products>

Ответы [ 3 ]

3 голосов
/ 16 марта 2011

Вот полное решение:

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

 <xsl:variable name="vProd1TotalPrice"
     select="sum(//Product[Name='X1']/Price)"/>

 <xsl:variable name="vProd2TotalPrice"
     select="sum(//Product[Name='X2']/Price)"/>

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

 <xsl:template match="Product">
  <xsl:copy>
   <xsl:apply-templates select="*[not(self::Product)]"/>
   <TotalPrice>
     <xsl:value-of select=
      "$vProd1TotalPrice *(Name='X1')
      +
       $vProd2TotalPrice *(Name='X2')
      "/>
   </TotalPrice>
   <xsl:apply-templates select="Product"/>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу XML:

<Products>
    <Product>
        <Name>X2</Name>
        <Price>1</Price>
        <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
            </Product>
            <Product>
                <Name>X2</Name>
                <Price>1</Price>
            </Product>
        </Product>
        <Product>
            <Name>X2</Name>
            <Price>1</Price>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
            </Product>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <Product>
                    <Name>X2</Name>
                    <Price>1</Price>
                </Product>
            </Product>
        </Product>
    </Product>
    <Description>
        <text>dsd</text>
    </Description>
    <Description>
        <text>dsd</text>
    </Description>
</Products>

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

<Products>
   <Product>
      <Name>X2</Name>
      <Price>1</Price>
      <TotalPrice>4</TotalPrice>
      <Product>
         <Name>X1</Name>
         <Price>1</Price>
         <TotalPrice>4</TotalPrice>
         <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <TotalPrice>4</TotalPrice>
         </Product>
         <Product>
            <Name>X2</Name>
            <Price>1</Price>
            <TotalPrice>4</TotalPrice>
         </Product>
      </Product>
      <Product>
         <Name>X2</Name>
         <Price>1</Price>
         <TotalPrice>4</TotalPrice>
         <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <TotalPrice>4</TotalPrice>
         </Product>
         <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <TotalPrice>4</TotalPrice>
            <Product>
               <Name>X2</Name>
               <Price>1</Price>
               <TotalPrice>4</TotalPrice>
            </Product>
         </Product>
      </Product>
   </Product>
   <Description>
      <text>dsd</text>
   </Description>
   <Description>
      <text>dsd</text>
   </Description>
</Products>

Объяснение :

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

Рекурсия не требуется.

0 голосов
/ 16 марта 2011

Еще раз спасибо, Димитр ... Я изменил xslt, чтобы сделать его немного общим ... теперь это выглядит так ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-16" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Product">
    <xsl:variable name="ProductLine" select="."/>
        <xsl:copy>
            <xsl:apply-templates select="*[not(self::Product)]"/>
            <TotalPrice>
                <xsl:value-of select="sum(//Product[Name=$ProductLine/Name]/Price)"/>
            </TotalPrice>
            <xsl:apply-templates select="Product"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Так что, если я дам измененный xml, как показано ниже.

<?xml version="1.0" encoding="UTF-8"?>
<Products>
    <Product>
        <Name>X2</Name>
        <Price>1</Price>
        <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
            </Product>
            <Product>
                <Name>X3</Name>
                <Price>1</Price>
            </Product>
        </Product>
        <Product>
            <Name>X2</Name>
            <Price>1</Price>
            <Product>
                <Name>X3</Name>
                <Price>1</Price>
            </Product>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <Product>
                    <Name>X2</Name>
                    <Price>1</Price>
                </Product>
            </Product>
        </Product>
    </Product>
    <Description>
        <text>dsd</text>
    </Description>
    <Description>
        <text>dsd</text>
    </Description>
</Products>

Это все еще дает мне вывод, как показано ниже.

<?xml version="1.0" encoding="UTF-16"?>
<Products>
    <Product>
        <Name>X2</Name>
        <Price>1</Price>
        <TotalPrice>3</TotalPrice>
        <Product>
            <Name>X1</Name>
            <Price>1</Price>
            <TotalPrice>3</TotalPrice>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <TotalPrice>3</TotalPrice>
            </Product>
            <Product>
                <Name>X3</Name>
                <Price>1</Price>
                <TotalPrice>2</TotalPrice>
            </Product>
        </Product>
        <Product>
            <Name>X2</Name>
            <Price>1</Price>
            <TotalPrice>3</TotalPrice>
            <Product>
                <Name>X3</Name>
                <Price>1</Price>
                <TotalPrice>2</TotalPrice>
            </Product>
            <Product>
                <Name>X1</Name>
                <Price>1</Price>
                <TotalPrice>3</TotalPrice>
                <Product>
                    <Name>X2</Name>
                    <Price>1</Price>
                    <TotalPrice>3</TotalPrice>
                </Product>
            </Product>
        </Product>
    </Product>
    <Description>
        <text>dsd</text>
    </Description>
    <Description>
        <text>dsd</text>
    </Description>
</Products>

Stackoverflow и эксперты здесь потрясающие ... Еще раз спасибо!

0 голосов
/ 16 марта 2011

Ну, чтобы дать вам направление ..

Вы можете начать с написания шаблона для элемента Product.

Используйте xsl:for-each и рекурсивно примените тот же шаблон. (проверить рекурсивные шаблоны)

И, как вы предложили, вам нужно будет умно использовать xsl:variables вместе с функцией sum().

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