Вложенные условные операторы if else в xpath

у меня есть этот XML-код:

<property id="1011">
    <leasehold>No</leasehold>
    <freehold>Yes</freehold>
    <propertyTypes>
        <propertyType>RESIDENTIAL</propertyType>
    </propertyTypes>
</property>

и я хочу создать оператор xpath, который совпадает со следующим вложенным блоком псевдокода if-else.

if( propertyTypes/propertyType == 'RESIDENTIAL') {
    if( leasehold == 'Yes' ){
        return 'Rent'
    } else
        return 'Buy'
    }
} else {
    if( leasehold == 'Yes' ){
        return 'Leasehold'
    } else
        return 'Freehold'
    }
}

Я видел что-то о методе Беккера, но я не могу следовать ему. XPath на самом деле не моя сильная сторона.

4 ответов


I. В XPath 2.0 это просто переводится как:

   if(/*/propertyTypes/propertyType = 'RESIDENTIAL')
    then
     (if(/*/leasehold='Yes')
       then 'Rent'
       else 'Buy'
     )
     else
       if(/*/leasehold='Yes')
         then 'Leasehold'
         else 'Freehold'

проверка на основе XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:sequence select=
   "if(/*/propertyTypes/propertyType = 'RESIDENTIAL')
   then
     (if(/*/leasehold='Yes')
       then 'Rent'
       else 'Buy'
     )
     else
       if(/*/leasehold='Yes')
         then 'Leasehold'
         else 'Freehold'
   "/>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному XML-документу:

<property id="1011">
    <leasehold>No</leasehold>
    <freehold>Yes</freehold>
    <propertyTypes>
        <propertyType>RESIDENTIAL</propertyType>
    </propertyTypes>
</property>

выражение XPath вычисляется и результат этой оценки копируется в выходные данные:

Buy

II. XPath 1.0 решение

в XPath 1.0 нет if оператора.

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

вот общий способ (впервые предложенный Джени Теннисон), чтобы произвести $stringA, когда условие $cond is true() и в противном случае произвести $stringB:

concat(substring($stringA, 1 div $cond), substring($stringB, 1 div not($cond)))

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

объяснение:

здесь мы используем тот факт, что по определению:

number(true()) = 1

и

number(false()) = 0

и

1 div 0 = Infinity

так, если $cond is false первый аргумент concat() выше:

 substring($stringA, Infinity)

и это пустая строка, потому что $stringA имеет конечное длина.

на другой стороне, если $cond is true() тогда первый аргумент concat() выше:

sibstring($stringA, 1) 

это просто $stringA.

так, в зависимости от значения $cond только один из двух аргументов concat() выше-непустая строка (соответственно $stringA или $stringB).

применяя эту общую формулу к конкретному вопросу, мы можем перевести первую половину большого условного выражения в:

concat(
           substring('rent',
                      1 div boolean(/*[leasehold='Yes'
                                     and
                                       propertyTypes/propertyType = 'RESIDENTIAL'
                                      ]
                                  )
                      ),
           substring('buy',
                      1 div not(/*[leasehold='Yes'
                                     and
                                       propertyTypes/propertyType = 'RESIDENTIAL'
                                      ]
                                  )
                      )
               )

это должно дать вам представление о том, как перевести все условное выражение в одно выражение XPath 1.0.

проверка на основе XSLT 1.0:

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

 <xsl:template match="/">
  <xsl:copy-of select=
   "concat(
           substring('rent',
                      1 div boolean(/*[leasehold='Yes'
                                     and
                                       propertyTypes/propertyType = 'RESIDENTIAL'
                                      ]
                                  )
                      ),
           substring('buy',
                      1 div not(/*[leasehold='Yes'
                                     and
                                       propertyTypes/propertyType = 'RESIDENTIAL'
                                      ]
                                  )
                      )
               )
   "/>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному XML-документу (выше), вычисляется выражение XPath и результат этой оценки копируется в выходные данные:

buy

Do Примечание:

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


метод Беккера для ваших данных следующий:

concat(substring('Rent',      1 div boolean(propertyTypes/propertyType ="RESIDENTIAL" and leasehold="Yes")),
       substring('Buy',       1 div boolean(propertyTypes/propertyType ="RESIDENTIAL" and leasehold="No")),
       substring('Leasehold', 1 div boolean(propertyTypes/propertyType!="RESIDENTIAL" and leasehold="Yes")),
       substring('Freehold',  1 div boolean(propertyTypes/propertyType!="RESIDENTIAL" and leasehold="No")))

провел весь день сегодня, но работает для меня это для Xpath 1.0:

concat(
substring(properties/property[@name="Headline"], 1, string-length(properties/property[@name="Headline"]) * 1), 
substring(properties/property[@name="Name"], 1, not(number(string-length(properties/property[@name="Headline"]))) * string-length(properties/property[@name="Name"]))
)

попробуй такое

if (condition) 
then 
  if (condition) stmnt 
  else stmnt 
else 
  if (condition) stmnt 
  else stmnt