2013-05-07 2 views
0

Еще раз проблема. У меня не очень хороший xml. Например следующее:Рекурсивная трансформация XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<Values> 
<record name='svc_sig'> 
<record name="sig_in"> 
    <array depth="1" name="rec_fields" type="record"> 
     <record> 
      <!-- Some irrelevant metadata information with value node name... --> 
      <value name="field_name">docTest</value> 
      <value name="field_type">record</value> 
      <value name="field_dim">0</value> 
      <array depth="1" name="rec_fields" type="record"> 
       <record javaclass="com.wm.util.Values"> 
        <!-- Some irrelevant metadata information with value node name... --> 
        <value name="field_name">doc.name</value> 
        <value name="field_type">string</value> 
        <value name="field_dim">0</value> 
       </record> 
      </array> 
     </record> 
     <record> 
      <value name="field_name">docListTest</value> 
      <value name="field_type">record</value> 
      <value name="field_dim">1</value> 
      <array depth="1" name="rec_fields" type="record"> 
       <record> 
        <value name="field_name">d0</value> 
        <value name="field_type">record</value> 
        <value name="field_dim">0</value> 
        <array depth="1" name="rec_fields" type="record"> 
         <record> 
          <value name="field_name">d0.name</value> 
          <value name="field_type">string</value> 
          <value name="field_dim">0</value> 
         </record> 
        </array> 
       </record> 
      </array> 
     </record> 
     <record> 
      <value name="field_name">packages_should_work</value> 
      <value name="field_type">recref</value> 
      <value name="field_dim">0</value> 
      <value name="rec_ref">data:packages</value> 
     </record> 
     <record> 
      <value name="field_name">packages_list_should_work</value> 
      <value name="field_type">recref</value> 
      <value name="field_dim">1</value> 
      <value name="rec_ref">data:packages</value> 
     </record> 
    </array> 
</record> 
</record> 
</Values> 

Для простоты мне нужно сопоставить этот XML к Java класса, который уже дал, и я не могу изменить его. Имея это в виду, я должен преобразовать этот xml в другой со значимыми именами. Например:

<sig_in> 
    <record> 
     <field_name>docTest</field_name> 
     <field_type>record</field_type> 
     <field_dim>0</field_dim> 
    </record> 
    <record> 
     <field_name>docListTest</field_name> 
     <field_type>record</field_type> 
     <field_dim>1</field_dim> 
    </record> 
    <record> 
     <field_name>packages_should_work</field_name> 
     <field_type>recref</field_type> 
     <field_dim>0</field_dim> 
    </record> 
    <record> 
     <field_name>packages_list_should_work</field_name> 
     <field_type>recref</field_type> 
     <field_dim>1</field_dim> 
    </record> 
</sig_in> 

До сих пор я создал что-то вроде этого:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" indent="yes" encoding="UTF-8" /> 
    <xsl:template match="/" name="service_signature"> 
     <sig_in> 
      <xsl:for-each select="Values/record[@name='svc_sig']/record[@name='sig_in']/array[@name]/record"> 
       <record> 
        <field_name><xsl:value-of select="value[@name='field_name']/text()"/></field_name> 
        <field_type><xsl:value-of select="value[@name='field_type']/text()"/></field_type> 
        <field_dim><xsl:value-of select="value[@name='field_dim']/text()"/></field_dim> 
       </record> 
      </xsl:for-each> 
     </sig_in> 
    </xsl:template> 

</xsl:stylesheet> 

В то время как он работает для основных элементов не будет работать для вложенных записей. Я мог бы создать xsl: for-each и перебрать каждый элемент, если тип является записью, но это не решит многое; потому что он может быть любым глубоким. Я знаю, что я должен использовать рекурсию, я просто не могу представить, как я могу это сделать в этом конкретном случае.

@Edit - Некоторые исправления для вложенных типов:

<record> 
    <field_name>docListTree</field_name> 
    <field_type>record</field_type> 
    <field_dim>1</field_dim> 
    <record> 
    <field_name>d0</field_name> 
    <field_type>record</field_type> 
    <field_dim>0</field_dim> 
    <record> 
     <field_name>d0.name</field_name> 
     <field_type>string</field_type> 
     <field_dim>0</field_dim> 
    </record> 
    </record> 
</record> 

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

@Edit: - Очень жаль, что я хотел сэкономить место, и мне не удалось показать сложность за стенами. Таким образом, каждая запись содержит узлы имен значений. Большинство из них содержат только бесполезную метаданные, которые мне не нужны. Также есть две записи: @name {sig_in, sig_out}, из которых мне нужно только sig_in, с информацией field_name, field_type, field_dim, вместе с вложенными записями. Я просмотрю все рекомендованные параметры и попытаюсь изменить их в соответствии с потребностями.

Благодарим за любую помощь! - Джо

+0

только, чтобы это ясно. Выход должен содержать любые записи из ввода без учета каких-либо условий? –

+0

Структура должна оставаться неизменной. Если запись вложена в другую, она также должна быть вложена в полученный xml. – Wrath

ответ

0

Попробуйте что-то вроде этого:

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

    <xsl:template match="value[@name]"> 
     <xsl:element name="{@name}"> 
      <xsl:value-of select="text()"/> 
     </xsl:element> 

    </xsl:template> 

    <xsl:template match="record"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy> 
    </xsl:template> 
    <xsl:template match="/*"> 
     <xsl:apply-templates /> 
    </xsl:template> 

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

Который будет генерировать Следующий вывод:

<?xml version="1.0"?> 
<record> 
    <field_name>docTest</field_name> 
    <field_type>record</field_type> 
    <field_dim>0</field_dim> 
    <record> 
    <field_name>doc.name</field_name> 
    <field_type>string</field_type> 
    <field_dim>0</field_dim> 
    </record> 
</record><record> 
    <field_name>docListTest</field_name> 
    <field_type>record</field_type> 
    <field_dim>1</field_dim> 
    <record> 
    <field_name>d0</field_name> 
    <field_type>record</field_type> 
    <field_dim>0</field_dim> 
    <record> 
     <field_name>d0.name</field_name> 
     <field_type>string</field_type> 
     <field_dim>0</field_dim> 
    </record> 
    </record> 
</record><record> 
    <field_name>packages_should_work</field_name> 
    <field_type>recref</field_type> 
    <field_dim>0</field_dim> 
    <rec_ref>data:packages</rec_ref> 
</record><record> 
    <field_name>packages_list_should_work</field_name> 
    <field_type>recref</field_type> 
    <field_dim>1</field_dim> 
    <rec_ref>data:packages</rec_ref> 
</record> 

Update лань к дополнительной информации в вопросе:

Вы можете легко положить в некоторых условиях в записи или значение шаблонов. Это то, что я понял: считать только записи, у которых есть запись с @name значением «sig_in».
Попробуйте это:

?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 

    <xsl:template match="value[@name = 'field_name' or 
          @name = 'field_type' or 
          @name = 'field_dim']"> 
     <xsl:element name="{@name}"> 
      <xsl:value-of select="text()"/> 
     </xsl:element> 

    </xsl:template> 

    <xsl:template match="record[descendant-or-self::record[@name='sig_in'] or 
        ancestor::record[@name='sig_in']]"> 
      <xsl:copy> 
       <xsl:apply-templates /> 
      </xsl:copy> 
    </xsl:template> 


    <xsl:template match="/*"> 
     <xsl:apply-templates /> 
    </xsl:template> 

    <xsl:template match="node()"> 
     <xsl:apply-templates select="node()" /> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Выглядит многообещающе, но подходит для каждого узла записи или значения, но мне нужны только конкретные. Это действительно снова моя ошибка, я просто попытался сэкономить много места, чтобы не вставить весь большой xml. Я обновлю оригинальный пример xml. – Wrath

+0

@Joey: Вы посмотрели обновление. Это учитывает записи только с именем '@ name = 'sig_in @ name =' sig_in'as родителем или дочерними элементами (любой глубиной). –

0

Этого XSLT способен генерировать вы вывесили результат:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" indent="yes" encoding="UTF-8" /> 
    <xsl:template match="/" name="service_signature"> 
    <sig_in> 
     <xsl:for-each select="/record[@name='sig_in']/array[@name]/record"> 
     <record> 
      <field_name><xsl:value-of select="value[@name='field_name']/text()"/></field_name> 
      <field_type><xsl:value-of select="value[@name='field_type']/text()"/></field_type> 
      <field_dim><xsl:value-of select="value[@name='field_dim']/text()"/></field_dim> 
     </record> 
     </xsl:for-each> 
    </sig_in> 
    </xsl:template> 

</xsl:stylesheet> 

Но, если вы хотите перебрать каждое и каждую запись, использование:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" indent="yes" encoding="UTF-8" /> 
    <xsl:template match="/" name="service_signature"> 
    <sig_in> 
     <xsl:for-each select="//array[@name]/record"> 
     <record> 
      <field_name><xsl:value-of select="value[@name='field_name']/text()"/></field_name> 
      <field_type><xsl:value-of select="value[@name='field_type']/text()"/></field_type> 
      <field_dim><xsl:value-of select="value[@name='field_dim']/text()"/></field_dim> 
     </record> 
     </xsl:for-each> 
    </sig_in> 
    </xsl:template> 

</xsl:stylesheet> 
0

Вот XSLT, что может помочь вам.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:strip-space elements="*"/> 
    <xsl:output indent="yes"/> 
    <xsl:template match="*"> 
     <xsl:apply-templates/> 
    </xsl:template> 
    <xsl:template match="record|value"> 
     <xsl:choose> 
      <xsl:when test="@name"> 
       <xsl:element name="{@name}"> 
        <xsl:apply-templates/> 
       </xsl:element>    
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy> 
        <xsl:apply-templates/> 
       </xsl:copy>    
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

С вашим XML:

<record name="sig_in"> 
    <array depth="1" name="rec_fields" type="record"> 
     <record> 
      <value name="field_name">docTest</value> 
      <value name="field_type">record</value> 
      <value name="field_dim">0</value> 
      <array depth="1" name="rec_fields" type="record"> 
       <record javaclass="com.wm.util.Values"> 
        <value name="field_name">doc.name</value> 
        <value name="field_type">string</value> 
        <value name="field_dim">0</value> 
       </record> 
      </array> 
     </record> 
     <record> 
      <value name="field_name">docListTest</value> 
      <value name="field_type">record</value> 
      <value name="field_dim">1</value> 
      <array depth="1" name="rec_fields" type="record"> 
       <record> 
        <value name="field_name">d0</value> 
        <value name="field_type">record</value> 
        <value name="field_dim">0</value> 
        <array depth="1" name="rec_fields" type="record"> 
         <record> 
          <value name="field_name">d0.name</value> 
          <value name="field_type">string</value> 
          <value name="field_dim">0</value> 
         </record> 
        </array> 
       </record> 
      </array> 
     </record> 
     <record> 
      <value name="field_name">packages_should_work</value> 
      <value name="field_type">recref</value> 
      <value name="field_dim">0</value> 
      <value name="rec_ref">data:packages</value> 
     </record> 
     <record> 
      <value name="field_name">packages_list_should_work</value> 
      <value name="field_type">recref</value> 
      <value name="field_dim">1</value> 
      <value name="rec_ref">data:packages</value> 
     </record> 
    </array> 
</record> 

Результат:

<?xml version="1.0" encoding="utf-8"?> 
<sig_in> 
    <record> 
     <field_name>docTest</field_name> 
     <field_type>record</field_type> 
     <field_dim>0</field_dim> 
     <record> 
     <field_name>doc.name</field_name> 
     <field_type>string</field_type> 
     <field_dim>0</field_dim> 
     </record> 
    </record> 
    <record> 
     <field_name>docListTest</field_name> 
     <field_type>record</field_type> 
     <field_dim>1</field_dim> 
     <record> 
     <field_name>d0</field_name> 
     <field_type>record</field_type> 
     <field_dim>0</field_dim> 
     <record> 
      <field_name>d0.name</field_name> 
      <field_type>string</field_type> 
      <field_dim>0</field_dim> 
     </record> 
     </record> 
    </record> 
    <record> 
     <field_name>packages_should_work</field_name> 
     <field_type>recref</field_type> 
     <field_dim>0</field_dim> 
     <rec_ref>data:packages</rec_ref> 
    </record> 
    <record> 
     <field_name>packages_list_should_work</field_name> 
     <field_type>recref</field_type> 
     <field_dim>1</field_dim> 
     <rec_ref>data:packages</rec_ref> 
    </record> 
</sig_in> 
Смежные вопросы