迭代数组并根据优先级选择

时间:2012-08-24 12:59:25

标签: xml xslt xpath xsl-fo

首先发布在这里!

好的..我的联系人XML如下:

<contact>
  <item>
    <ContactData type="String">+4444444444</ContactData>
    <Type type="String">1</Type>
  </item>
  <item>
    <ContactData type="String">+9999999999</ContactData>
    <Type type="String">3</Type>
  </item>
  <item>
    <ContactData type="String">anyone123452154@gmail.com</ContactData>
    <Type type="String">4</Type>
  </item>
  <item>
    <ContactData type="String">+5554444444</ContactData>
    <Type type="String">2</Type>
  </item>
</contact>

如您所见,类型4是电子邮件,类型1是电话号码,类型2是传真,类型3是手机号码。

所以这是我的情景:

我(可能)需要遍历所有这些节点。检查是否有电话号码(最高优先级)并选择它。如果没有电话号码,我们需要检查手机号码(第二高优先级)。如果手机号码不可用,我们选择电子邮件(或我们什么都不做)。我怎样才能实现它?

谢谢..

4 个答案:

答案 0 :(得分:2)

与Tim C的答案类似,但附加要求仅返回Type 1,Type 3或Type 4项目。

XSLT 1.0

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

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

    <xsl:template match="contact">
        <xsl:variable name="vContacts">
            <xsl:apply-templates select="item[Type='1' or Type='3' or Type='4']">
                <xsl:sort select="Type"/>
            </xsl:apply-templates>                          
        </xsl:variable>
        <results><xsl:value-of select="$vContacts/item[1]/ContactData"/></results>
    </xsl:template>

</xsl:stylesheet>

<强>输出

<results>+4444444444</results>

答案 1 :(得分:1)

实现此目标的一种方法是使用 xsl:for-each 简单地遍历元素,并对的值进行排序输入元素。然后你可以简单地选择第一个元素。

这是完整的XSLT

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

   <xsl:template match="contact">
      <xsl:for-each select="item[ContactData != '']">
         <xsl:sort select="Type" order="ascending" />
         <xsl:if test="position() = 1">
            <xsl:value-of select="ContactData" />
         </xsl:if>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

+4444444444

如果您要删除电话号码,则应返回手机号码。也将其删除,并返回电子邮件地址。

编辑:如果您需要排除传真号码,可以将 xsl:for-each 更改为以下内容:

<xsl:for-each select="item[Type != '2'][ContactData != '']">

或者,如果您只想说明手机,手机或电子邮件,那么您可以执行以下操作

<xsl:for-each select="item[Type = '1' or Type = '3' or Type = '4'][ContactData != '']">

答案 2 :(得分:0)

这可以通过单个XPath表达式获得 - 您根本不需要XSLT

  ( /*/item[Type = 1]
   |
    /*[not(item[Type = 1])]/item[Type = 3]
   |
    /*[not(item[Type = 1 or Type = 3])]/item[Type = 4]
    )
     /ContactData/text()

基于XSLT的验证

<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="/">
     <xsl:copy-of select=
     "(/*/item[Type = 1]
   |
    /*[not(item[Type = 1])]/item[Type = 3]
   |
    /*[not(item[Type = 1 or Type = 3])]/item[Type = 4]
    )
     /ContactData/text()"/>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<contact>
  <item>
    <ContactData type="String">+4444444444</ContactData>
    <Type type="String">1</Type>
  </item>
  <item>
    <ContactData type="String">+9999999999</ContactData>
    <Type type="String">3</Type>
  </item>
  <item>
    <ContactData type="String">anyone123452154@gmail.com</ContactData>
    <Type type="String">4</Type>
  </item>
  <item>
    <ContactData type="String">+5554444444</ContactData>
    <Type type="String">2</Type>
  </item>
</contact>

评估XPath表达式并将选定的节点复制到输出中:

+4444444444

答案 3 :(得分:0)

或者,如果你有XPath 2.0,你可以按优先顺序将所需的类型编写为(1,3,4),迭代类型并选择第一个类型:

/contact/(for $i in (1,3,4) return item[Type = $i])[1]/ContactData/text()

或者展开循环:

/contact/(*[Type = 1], *[Type = 3], *[Type = 4])[1]/ContactData/text()