2012-07-02 2 views
2

Мой вход XML-состоит в следующем,Дисплей Серийный номер с помощью XSLT

<root> 
    <entry> 
     <type>U</type> 
     <value>111</value> 
    </entry> 
    <entry> 
     <type>X</type> 
     <value>222</value> 
    </entry> 
    <entry> 
     <type>E</type> 
     <value>333</value> 
    </entry> 
    <entry> 
     <type>Q</type> 
     <value>444</value> 
    </entry> 
    <entry> 
     <value>555</value> 
    </entry> 
    <entry> 
     <value>666</value> 
    </entry> 
</root> 

Выход я требуется,

<ROOT> 
    <ENTRY> 
     <SLNO>1</SLNO> 
     <VALUE>111</VALUE> 
    </ENTRY> 
    <ENTRY> 
     <SLNO>1</SLNO> 
     <VALUE>222</VALUE> 
    </ENTRY> 
    <ENTRY> 
     <SLNO>1</SLNO> 
     <VALUE>333</VALUE> 
    </ENTRY> 
    <ENTRY> 
     <SLNO>2</SLNO> 
     <VALUE>444</VALUE> 
    </ENTRY> 
    <ENTRY> 
     <SLNO>3</SLNO> 
     <VALUE>555<VALUE> 
    </ENTRY> 
    <ENTRY> 
     <SLNO>4</SLNO> 
     <VALUE>666</VALUE> 
    </ENTRY> 
</ROOT> 

Требование заключается в получении новых SLNO для других, чем X, E, Y типов и K, а также если сам тег типа отсутствует. Для всех остальных типов нам нужно отобразить новый серийный номер.

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

Как я могу это достичь?

Мой пример кода XSL является н.у.м. следует,

<xsl:for-each select="/ROOT/ENTRY"> 
    <xsl:if test="(TYPE != 'X') and (TYPE != 'E')">    
     <xsl:text><![CDATA[<SLNO>]]></xsl:text> 


     <xsl:if test="((type != 'X') and (type != 'E') and (type != 'Y') and (type != 'K'))"> 
      <xsl:value-of select="count(preceding::type[((. != 'X' and . != 'E' and . != 'Y' and . !='K') or . ='')]) + 1" /> 
     </xsl:if>                

     <xsl:if test="(type = 'X') or (type = 'E') or (type = 'Y') or (type = 'K')"> 
      <xsl:value-of select="count(preceding::type[(. != 'X' and . != 'E' and . != 'Y' and . !='K')])" />               
     </xsl:if> 



     <xsl:text><![CDATA[</SLNO>]]></xsl:text> 
    </xsl:if> 
    <!-- Printing remaining values --> 
</xsl:for-each> 

Проблема с этим кодом является, я не получаю SLNO для записей, которые не имеют тип тега.

Пожалуйста, помогите.

+2

Ваш вопрос полностью правильно. Вы указываете «X, Y, K и L» в вопросе, но есть ссылка на «E» в XSLT, но не «L» –

+0

@Tim, вы правы, я его обновил. Прости. – Wilz

+1

@Wilz: В вашем коде вы генерируете * текст *, который похож на разметку - это не создает в любом случае XML-документ, который вы хотите получить. Изучите * never *, чтобы создать текст с разметкой и похожим текстом. –

ответ

3

Предупреждение :

Код, указанный в этом документе вопрос не является синтаксически законным XSLT - нет инструкции XSLT <xsl:type-of> на этом языке.

Кроме того, этот код генерирует текст, который выглядит как открывающий и закрывающий теги элементов.

Никогда не делайте такую ​​вещь, когда хотите сгенерировать элемент - тест не разметка - это просто ... текст; и сгенерированный вывод - это не то, что вы хотели.


Решение:

Это преобразование:

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

<xsl:template match="entry"> 
    <entry> 
    <slno> 
    <xsl:value-of select= 
    "count((. 
      | 
       preceding-sibling::entry) 
       [not(type) 
       or 
       not(contains('+X+E+Y+K+', concat('+', type, '+'))) 
       ] 
      )"/> 
    </slno> 
    <xsl:apply-templates select="node()[not(self::type)]"/> 
    </entry> 
</xsl:template> 
</xsl:stylesheet> 

при нанесении на поставленном XML документа:

<root> 
    <entry> 
     <type>U</type> 
     <value>111</value> 
    </entry> 
    <entry> 
     <type>X</type> 
     <value>222</value> 
    </entry> 
    <entry> 
     <type>E</type> 
     <value>333</value> 
    </entry> 
    <entry> 
     <type>Q</type> 
     <value>444</value> 
    </entry> 
    <entry> 
     <value>555</value> 
    </entry> 
    <entry> 
     <value>666</value> 
    </entry> 
</root> 

производит разыскиваемого, правильный результат:

<root> 
    <entry> 
     <slno>1</slno> 
     <value>111</value> 
    </entry> 
    <entry> 
     <slno>1</slno> 
     <value>222</value> 
    </entry> 
    <entry> 
     <slno>1</slno> 
     <value>333</value> 
    </entry> 
    <entry> 
     <slno>2</slno> 
     <value>444</value> 
    </entry> 
    <entry> 
     <slno>3</slno> 
     <value>555</value> 
    </entry> 
    <entry> 
     <slno>4</slno> 
     <value>666</value> 
    </entry> 
</root> 
+0

Большое спасибо за решение Dimitre, и он отлично работает. Можете ли вы PLZ предоставить мне некоторую ссылку, чтобы узнать XSL, так как я новичок в XSLT. – Wilz

+0

@Wilz: Добро пожаловать. Этот ответ содержит указатели на хорошие ресурсы XSLT: http://stackoverflow.com/a/341589/36305 –

0

в чеке

(TYPE != 'X') and (TYPE != 'E') 

вам необходимо включить оператор 'ИЛИ' для ЗАЯВКИ узлов, которые не имеют узел TYPE»

что-то вроде

((TYPE != 'X') and (TYPE != 'E')) or count(TYPE) = 0 
+0

Пробовал следующее, но не работает, Wilz

1
  • Не EVER использование для элементов вывода XML. Когда-либо.Это просто плохо и неправильно (и уродливо, но уродливый даже не аргумент здесь).
  • Не использовать <xsl:for-each>. Использовать <xsl:template>/<xsl:apply-templates>
  • Вы можете использовать translate() в свою очередь, что см. Ниже. ПРЕДУПРЕЖДЕНИЕ Этот ярлык будет работать только в том случае, если у вас есть однобуквенные типы.
  • Думайте, если вы действительно необходимо в верхнем регистре этих имен элементов. Это не выглядит для меня необходимым изменением. Хранение оригинального корпуса намного проще, потому что вы можете использовать identity template. Также см. Dimitre's answer.

Эта таблица стилей:

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

    <xsl:template match="root"> 
    <ROOT> 
     <xsl:apply-templates select="entry" /> 
    </ROOT> 
    </xsl:template> 

    <xsl:template match="entry"> 
    <ENTRY> 
     <SLNO> 
     <xsl:value-of select=" 
      count(
      (. | preceding-sibling::entry)[not(type and translate(type, 'EKXY', '') = '')] 
     ) 
     " /> 
     </SLNO> 
     <xsl:apply-templates select="value" /> 
    </ENTRY> 
    </xsl:template> 

    <xsl:template match="value"> 
    <VALUE> 
     <xsl:value-of select="." /> 
    </VALUE> 
    </xsl:template> 
</xsl:stylesheet> 

производит:

<ROOT> 
    <ENTRY> 
    <SLNO>1</SLNO> 
    <VALUE>111</VALUE> 
    </ENTRY> 
    <ENTRY> 
    <SLNO>1</SLNO> 
    <VALUE>222</VALUE> 
    </ENTRY> 
    <ENTRY> 
    <SLNO>1</SLNO> 
    <VALUE>333</VALUE> 
    </ENTRY> 
    <ENTRY> 
    <SLNO>2</SLNO> 
    <VALUE>444</VALUE> 
    </ENTRY> 
    <ENTRY> 
    <SLNO>3</SLNO> 
    <VALUE>555</VALUE> 
    </ENTRY> 
    <ENTRY> 
    <SLNO>4</SLNO> 
    <VALUE>666</VALUE> 
    </ENTRY> 
</ROOT> 
+0

Tomalak: Хороший ответ, но он не дает требуемого результата. Кроме того, использование 'translate()' таким образом будет считать ' XXXY', что не требуется. –

+0

@Dimitre Вопрос указывает однобуквенные типы, поэтому я взял это как ссылку. OP * не оставлял места для угадывания, так что это одно возможное решение. Но вы правы, многобуквенные типы * заставили бы мой код терпеть неудачу. Я добавил примечание с этим предупреждением. Ошибка подсчета в моей логике исправлена. – Tomalak

+0

Tomalak: Теперь, когда вы исправили исходное решение и включили в меня предупреждение +1. По-прежнему верно, что более общее решение применимо не только к типам документов XML, с которыми работает ограниченное решение. –

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