2015-09-21 3 views
1

У меня проблема с преобразованием xsl.XML/XSL: xpath и условие, когда/иначе

Вот XML:

<?xml version="1.0" encoding="windows-1252"?> 
<accounts> 
    <account> 
    <name>ryan</name> 
    <pass>password</pass> 
    <date></date> 
    <numbers> 
     <number>19</number> 
    </numbers> 
    <numbers> 
     <number>2</number> 
    </numbers> 
    <numbers> 
     <number>20</number> 
    </numbers> 
    </account> 
    <account> 
    <name>lift</name> 
    <pass>azerty</pass> 
    <date>27/05/2015</date> 
    <numbers> 
    </numbers> 
    </account> 
</accounts> 

Вот XSL:

<?xml version="1.0" encoding="windows-1252"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > 

     <xsl:output method="xml" indent="yes" encoding="windows-1252"/> 
     <xsl:strip-space elements="*"/> 

     <xsl:variable name="newline"> 
      <xsl:text/> 
     </xsl:variable> 

     <xsl:template match="/"> 
      <accounts> 
       <xsl:for-each select="accounts/account"> 
        <account> 
         <xsl:for-each select="*[not(self::numbers)]"> 
          <xsl:choose> 
           <xsl:when test="count(*|text()[string-length(normalize-space(.))>0])"> 
            <xsl:copy> 
             <xsl:apply-templates/> 
            </xsl:copy> 
           </xsl:when> 
           <xsl:otherwise> 
            <xsl:copy> 
             <xsl:attribute name="xsi:nil">true</xsl:attribute> 
            </xsl:copy> 
           </xsl:otherwise> 
          </xsl:choose>      
         </xsl:for-each> 
         <xsl:call-template name="t_number"/>      
        </account> 
       </xsl:for-each> 
      </accounts> 
     </xsl:template> 

     <xsl:template name="t_number" match="numbers"> 
      <xsl:choose> 
       <xsl:when test="count(number)"> 
        <numbers> 
         <xsl:for-each select="numbers/number"> 
          <number> 
           <xsl:value-of select="." /> 
          </number> 
         </xsl:for-each>       
        </numbers> 
       </xsl:when> 
       <xsl:otherwise> 
        <numbers xsi:nil="true"></numbers> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:template> 
    </xsl:stylesheet> 

Вот что у меня есть:

<?xml version="1.0" encoding="windows-1252"?> 
<accounts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <account> 
     <name>ryan</name> 
     <pass>password</pass> 
     <date xsi:nil="true"> 
     </date> 
     <numbers xsi:nil="true"></numbers> 
    </account> 
    <account> 
     <name>lift</name> 
     <pass>azerty</pass> 
     <date>27/09/2012</date> 
     <numbers xsi:nil="true"></numbers> 
    </account> 
</accounts> 

И что я хочу:

<?xml version="1.0" encoding="windows-1252"?> 
<accounts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <account> 
     <name>ryan</name> 
     <pass>password</pass> 
     <date xsi:nil="true"> 
     </date> 
     <numbers> 
      <number>19</number> 
      <number>2</number> 
      <number>20</number> 
     </numbers> 
    </account> 
    <account> 
     <name>lift</name> 
     <pass>azerty</pass> 
     <date>27/09/2012</date> 
     <numbers xsi:nil="true"></numbers> 
    </account> 
</accounts> 

Вы можете мне помочь? Функция подсчета работает странно.

ответ

1

Ваш узел контекста для выражения

<xsl:when test="count(number)"> 

неправильно. Когда вы звоните через <xsl:call-template name="t_number"/>, вы все еще внутри account. Таким образом,

<xsl:when test="count(numbers/number) gt 0"> 

должен сделать трюк. (Я бы предпочел «ГТ 0», потому что на мой взгляд, более удобным для чтения.)

Edit: Насколько я вижу, шаблон «t_numbers» вызывается только один раз, и через <xsl:call-template name="t_number"/>. Возможно, вам стоит удалить match="numbers", чтобы избежать путаницы.

+0

Синтаксис 'gt' еще не был доступен в XSLT 1.0 (OP использует 1.0), это функция XPath 2.0, возможно, вы имели в виду' > ', который также может быть записан как'> '(нет необходимости убегать)? – Abel

+0

Он работает, спасибо! Но почему вы предпочитаете> или gt>? просто личный выбор? – gon

+0

@Abel Я иногда забываю, что такое XPath 2. Вы правы,> выполнили бы эту работу. @gon Существуют различные способы тестирования, если присутствует (дочерний) узел. Лично мне нравится: «Считать узлы xy и вернуть true, если их больше нуля» ('count (number)> 0') больше, чем« Возвращать true, если есть что подсчитать »(' count (number) '), который это то, что у вас было. Однако это просто личный вкус. – cis

1

Как насчет этого пути?

XSLT-1,0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="/accounts"> 
    <accounts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
     <xsl:apply-templates select="@*|node()"/> 
    </accounts> 
</xsl:template> 

<xsl:template match="account"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()[not(self::numbers)]"/> 
     <numbers> 
      <xsl:choose> 
       <xsl:when test="numbers/number"> 
        <xsl:apply-templates select="numbers/number"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:attribute name="xsi:nil">true</xsl:attribute> 
       </xsl:otherwise> 
      </xsl:choose> 
     </numbers> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="date[not(string())]"> 
    <date xsi:nil="true"/> 
</xsl:template> 

</xsl:stylesheet> 

Примечание:
шаблон согласования "/accounts" могут быть удалены, и результат будет семантически идентичны.

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