2013-11-29 4 views
0

я folowing структуры XML:Копирование и перегруппировки узлы XML с помощью XSLT

<root> 
    <product> 
     <name> 
      <book1>data for book1</book1> 
      <book12>data for book12</book12> 
      <book13>data for book13</book13> 
      <book14>data for book14</book14> 
     </name> 
     <info> 
      <data1>data for data1</data1> 
      <data2>data for data2</data2> 
      <data3>data for data3<data3> 
      <data4>data for data4</data4> 
      <data5>data for data5</data5> 
      <data n+1>data n+1</data n+1> 
     </info> 

     <pictures> 
      <pic1>data for pic1</pic1> 
      <pic2>data for pic2</pic2> 
      <pic3>data for pic3</pic3> 
      <pic4>data for pic4</pic4> 
      <pic n+1>data for pic n+1</pic n+1> 
     </pictures> 

    </product> 

    <product> 
    . 
    . 
    . 
    . 
    . 
    </product> 
    . 
    . 
    . 
    . 
</root> 

Теперь я должен был бы скопировать данные 5, book14 и весь узел фотографий внутри каждого продукта узла так, что вывод XML будет выглядеть следующим образом:

<root> 
    <product> 
     <node_that_i_would_name_1> 
      <node_that_i_would_name_2> 
      <node_that_i_would_name_3> 
       <node_that_i_would_name_4> 
        <book14>data for book14</book14> 
       </node_that_i_would_name_4>    
       <node_that_i_would_name_5> 
        <data5>data for data5</data5> 
       </node_that_i_would_name_5>  
       <picturesA> 
        <pic1A> 
        <pic2A> 
        <pic3A> 
        <pic4A> 
        <pic n+1A> 
       </picturesA> 
       <empty_node_at_the_end_that_i_will_name></empty_node_at_the_end_that_i_will_name> 
      </node_that_i_would_name_3> 
      </node_that_i_would_name_2> 
     </node_that_i_would_name_1> 
     <name> 
      <book1>data for book1</book1> 
      <book12>data for book12</book12> 
      <book13>data for book13</book13> 
      <book14>data for book14</book14> 
     </name> 
     <info> 
      <data1>data for data1</data1> 
      <data2>data for data2</data2> 
      <data3>data for data3<data3> 
      <data4>data for data4</data4> 
      <data5>data for data5</data5> 
      <data n+1>data n+1</data n+1> 
     </info> 

     <pictures> 
      <pic1>data for pic1</pic1> 
      <pic2>data for pic2</pic2> 
      <pic3>data for pic3</pic3> 
      <pic4>data for pic4</pic4> 
      <pic n+1>data for pic n+1</pic n+1> 
     </pictures> 

    </product> 

    <product> 
    . 
    . 
    . 
    . 
    . 
    </product> 
    . 
    . 
    . 
    . 
</root> 

Каждая вещь должна оставаться неизменной, только эти данные должны быть скопированы и восстановлены способом, указанным выше в узлах. Есть ли простой способ сделать это с помощью xslt?

+0

Ответ на ваш вопрос почти наверняка «да», но тот, кто разработал этот формат XML, на самом деле не делает вашу жизнь легкой - если есть много элементов для сестер, которые представляют один и тот же тип данных, тогда это имело бы смысл чтобы дать им одинаковое имя и отличить их от атрибута, а не от кодирования содержимого в именах элементов (то есть '', а не ' ') ... –

ответ

3

Когда вы когда-нибудь проблему, как это, ваша первая мысль должна быть Identity Transform

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

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

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

<xsl:template match="product"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*" /> 
     <!-- Code to create new nodes and create extra copies of existing ones goes here --> 
     <xsl:apply-templates select="node()"/> 
    </xsl:copy> 

EDIT:. Заметьте, что атрибуты должны быть скопированы через перед любыми элементами!

Например, чтобы создать копию book14 элемента внутри нового элемента, вы бы просто добавить этот код:

<newnode1> 
    <xsl:apply-templates select="name/book14"/> 
</newnode1> 

Для элементов изображения, чтобы позволить этому быть скопировано с дополнительным суффикс имени элемента, вы бы шаблон, чтобы соответствовать дочерние элементы с (опционально) параметр, который затем будет использоваться при создании имени элемента

<xsl:template match="pictures/*"> 
    <xsl:param name="suffix" /> 
    <xsl:element name="{concat(local-name(), $suffix)}"> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:element> 
</xsl:template> 

Этот шаблон затем будет использоваться в двух differe nt мест. Тот, где он соответствует структуре обычно, и тот, где вы хотите создать дополнительную копию. Но в последнем случае необходимо установить параметр:

<xsl:apply-templates select="pictures/*"> 
    <xsl:with-param name="suffix" select="'A'" /> 
</xsl:apply-templates> 

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <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="@*"/> 
     <newnode> 
      <newnode1> 
       <xsl:apply-templates select="name/book14"/> 
      </newnode1> 
      <newnode2> 
       <xsl:apply-templates select="info/data5"/> 
      </newnode2> 
      <picturesA> 
       <xsl:apply-templates select="pictures/*"> 
        <xsl:with-param name="suffix" select="'A'" /> 
       </xsl:apply-templates> 
      </picturesA> 
     </newnode> 
     <xsl:apply-templates select="node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="pictures/*"> 
     <xsl:param name="suffix" /> 
     <xsl:element name="{concat(local-name(), $suffix)}"> 
     <xsl:apply-templates select="@*|node()"/> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Большое спасибо, вы сделали это настолько простым для понимания. Одна коррекция tho, в конце должна быть внутри него self xsl: копировать или давать и ошибки. Наверное, просто маленькая опечатка, но ваш ответ прекрасен. 10. Еще один вопрос. Есть ли способ, которым я мог бы добавить A в скопированные узлы изображений внутри, поэтому я бы получил узлы с именем pic1A, pic2A ..и так далее при копировании на новое место? – eoglasi

+0

Что касается опечатки, о которой я упоминал выше, кажется, что я сделал опечатку TIM C: D, поэтому ваш код работает так, как написано. Благодарю. – eoglasi

+0

Собственно, вы правы. Возникла потенциальная ошибка, которая могла возникнуть, если элемент ** product ** имел атрибуты на нем. Считается ошибкой добавлять атрибуты к выходному элементу, если дочерние элементы уже добавлены к нему. Я исправил свой образец XSLT, чтобы справиться с этим правильно сейчас! –

Смежные вопросы