XPath中嵌套的条件if else语句

9

我有这个XML:

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

我希望创建一个与以下嵌套if-else伪代码块相同的xpath语句。

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

我看到过有关贝克尔方法的内容,但我并没有完全理解。XPath 确实不是我的强项。

4个回答

23

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 表达式来实现条件语句,但这更加棘手,表达式可能不太可读和易于理解。

这里是一种通用方式(最初由 Jeni Tennison 提出),可以在条件 $condtrue() 时生成 $stringA,否则生成 $stringB

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

这个公式的主要成就之一是它可以适用于任意长度的字符串,而不需要指定长度。

解释:

在这里,我们利用了以下定义:

number(true()) = 1

而且

number(false()) = 0
并且那个。
1 div 0 = Infinity

因此,如果$condfalse,则上面concat()的第一个参数是:

 substring($stringA, Infinity)

这是一个空字符串,因为$stringA有限长度。

另一方面,如果$condtrue(),那么上面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

请注意:

如果您决定将具体字符串替换为长度与原始字符串不同的其他字符串,则只需在上面的XPath 1.0表达式中替换这些字符串,无需担心指定任何长度。


很好的解释。有没有办法将节点的长度作为$cond添加? - Daniel
@dan,如之前所述,这并不是必要的。因此,即使字符串的长度未知或随时间变化,该表达式仍然表达了所需的条件评估。是的,可以涉及字符串的长度,但包含它们的表达式非常脆弱且依赖于长度。 - Dimitre Novatchev

2

Becker的数据处理方法如下:

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")))

choroba,您可能对更通用的XPath 1.0表达式感兴趣,它不需要指定长度(并且每当我们想要使用不同的字符串作为结果时进行修改)。 - Dimitre Novatchev

1

今天我花了一整天的时间,但对于我来说这很管用,这是针对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"]))
)

0

试试这个

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接