2013-07-31 4 views
0

У меня есть документ XML с записями, которые имеют отдельные поля для тегов на английском и испанском языках. Отдельные метки разделяются точкой с запятой.Выравнивание полей по позиции с использованием XSLT

<collections> 
    <collection name="anyCollection"> 
    <record> 
     <field name="materia">comida; bebida; fiesta</field> 
     <field name="subject">food; drink; party</field> 
     <field name="recordid">abc0001</field> 
    </record> 
    <record> 
     <field name="materia">comida; bebida; fiesta</field> 
     <field name="subject">food; drink; party</field> 
     <field name="recordid">abc0002</field> 
    </record> 
    <record> 
     <field name="materia">comida; bebida; fiesta</field> 
     <field name="subject">food; drink; party</field> 
     <field name="recordid">abc0003</field> 
    </record> 
    <record> 
     <field name="materia">fiesta; sombreros; música; baile; agua; cerveza; sopa</field> 
     <field name="subject">party; hats; music; dance; water; beer; soup</field> 
     <field name="recordid">abc0004</field> 
    </record> 
    <record> 
     <field name="materia">comida; bebida; fiesta; sombreros; música</field> 
     <field name="subject">food; drink; party; hats; music</field> 
     <field name="recordid">abc0005</field> 
    </record> 
    <record> 
     <field name="materia">comida; bebida; cerveza; agua</field> 
     <field name="subject">food; drink; beer; water</field>    
     <field name="recordid">abc0006</field> 
    </record>   
    <record> 
     <field name="materia">fiesta; sombreros; música; baile; agua; cerveza</field> 
     <field name="subject">party; hats; music; dance; water; beer</field> 
     <field name="recordid">abc0007</field> 
    </record>  
    </collection> 
</collections> 

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

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"  
    version="2.0"> 

    <xsl:variable name="field"> 
    <xsl:for-each 
     select="collections/collection[@name='anyCollection']/record"> 
     <record> 
     <xsl:for-each select="field"> 
      <field> 
      <xsl:for-each select="tokenize(.[@name='materia'],';')"> 
       <materia> 
       <xsl:value-of select="."/> 
       </materia> 
      </xsl:for-each> 
      <xsl:for-each select="tokenize(.[@name='subject'],';')"> 
       <subject> 
       <xsl:value-of select="."/> 
       </subject> 
      </xsl:for-each> 
      </field> 
     </xsl:for-each> 
     </record> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:variable name="align">   
    <xsl:for-each select="$field/record/field">   
     <languagePair1>     
     <xsl:for-each select="materia[1]">      
      <xsl:value-of select="."/> 
      <xsl:text>_</xsl:text>  
     </xsl:for-each> 
     <xsl:for-each select="subject[1]">      
      <xsl:value-of select="."/> 
      <xsl:text>&#10;</xsl:text>  
     </xsl:for-each> 
     </languagePair1> 
     <languagePair2> 
     <xsl:for-each select="materia[2]">      
      <xsl:value-of select="."/> 
      <xsl:text>_</xsl:text>  
     </xsl:for-each>            
     <xsl:for-each select="subject[2]">      
      <xsl:value-of select="."/> 
      <xsl:text>&#10;</xsl:text>  
     </xsl:for-each>        
     </languagePair2> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:template match="/">    
    <xsl:for-each-group select="$align/languagePair1" group-by=".">   
     <xsl:value-of select="current-grouping-key()"/>   
    </xsl:for-each-group> 
    <xsl:for-each-group select="$align/languagePair2" group-by=".">   
     <xsl:value-of select="current-grouping-key()"/>    
    </xsl:for-each-group> 
    </xsl:template> 

</xsl:stylesheet> 

Вот основной выход я хочу:

comida_food 

bebida_drink 

fiesta_party 

sombreros_hats 

música_music 

мне также нужно выводить recordid S, связанных с каждым тегом, но я не был в состоянии включить это в таблицу стилей еще.

С этой информацией добавил, желаемый результат будет выглядеть следующим образом:

comida_food 
abc0001 
abc0002 
abc0003 
abc0005 
abc0006 

bebida_drink 
abc0001 
abc0002 
abc0003 
abc0005 
abc0006 

fiesta_party 
abc0001 
abc0002 
abc0003 
abc0004 
abc0005 
abc0007 

sombreros_hats 
abc0004 
abc0005 
abc0007 

música_music 
abc0004 
abc0005 
abc0007 
+0

Обновленный ввод XML, чтобы лучше отражать структуру мой набор данных. – tat

+0

Обновленный вывод для отражения ввода XML. – tat

ответ

1

Хороший случай использования Fn: для каждого-пары в XPath 3.0:

for-each-pair(
    tokenize($materia, '; '), 
    tokenize($subject, '; '), 
    function($x, $y) { $x || '_' || $y || '&#xa;' }) 

Доступный в Saxon-PE 9.5.1.1.

+0

Спасибо. Я с нетерпением жду этого! – tat

0

я могу получить вывод, который вы хотите с помощью следующего кода:

<xsl:stylesheet version="2.0" exclude-result-prefixes="xs" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 


<xsl:output method="text"/> 

<xsl:template match="/"> 
    <xsl:for-each-group select="collections/collection[@name = 'anyCollection']/record" group-by="tokenize(field[@name = 'materia'], '; ')"> 
    <xsl:variable name="pos" select="position()"/> 
    <xsl:variable name="subjects" select="tokenize(field[@name = 'subject'], '; ')"/> 
    <xsl:value-of select="concat(current-grouping-key(), '_', $subjects[$pos]), current-group()/field[@name = 'recordid']" separator="&#10;"/> 
    <xsl:text>&#10;&#10;</xsl:text> 
    </xsl:for-each-group> 
</xsl:template> 

</xsl:stylesheet> 

, что хватит ли? Я не уверен, каким образом вы хотите, чтобы код был динамическим, я предположил, что вы знаете атрибуты name интересующих вас элементов field (то есть materia, subject).

+0

Спасибо. Однако это решение, похоже, работает только для первой записи в серии. Счет 'position()' в переменной '$ pos' не соответствует позиции токеновских узлов, а скорее последовательности записей (т. Е. Счетчик не сбрасывается для каждой новой записи). – tat

+0

Думаю, мне нужно обновить свой входной XML, чтобы лучше отражать данные, с которыми я работаю. – tat

1

Использование Fn: для каждого-пары в XPath 3.0 с Saxon-PE 9.5.1.1, требуемый выход генерируется по следующей таблице стилей:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0"> 

    <xsl:output method="text"/> 
    <xsl:template match="/"> 
    <xsl:for-each-group select="collections/collection[@name = 'anyCollection']/record" 
     group-by="for-each-pair(
     tokenize(field[@name = 'materia'], '; '), 
     tokenize(field[@name = 'subject'], '; '), 
     function($x, $y) { $x || '_' || $y || '&#xa;' })"> 

     <xsl:value-of select="current-grouping-key()"/> 

     <xsl:for-each-group select="current-group()" group-by="field[@name='recordid']"> 
     <xsl:sort select="substring(translate(current-grouping-key(),'ÁÉÍÓÚÜáéíóúü','AEIOUUaeiouu'),4)" data-type="number"/>     
     <xsl:value-of select="current-grouping-key()"/> 
     <xsl:text>&#10;</xsl:text>  
     </xsl:for-each-group> 

     <xsl:text>&#10;</xsl:text>      
    </xsl:for-each-group> 
    </xsl:template> 
</stylesheet> 
Смежные вопросы