使用XSLT查找给定一组参数的节点

时间:2010-06-17 16:07:10

标签: xml xslt xpath

对标题感到抱歉 - 不知道如何说出来。

基本上我有一些像这样的XML:

<countries>
    <country handle="bangladesh"/>
    <country handle="india"/>
    <country handle="pakistan"/>
</countries>

这样的一些XSLT(不起作用):

<xsl:template match="/countries">
    <xsl:param name="popular"/>        
    <xsl:apply-templates select="country[count($popular/country[@handle = current()/@handle]) &gt; 0]" />
</xsl:template>    
<xsl:template match="/countries/country">
    …
</xsl:template>

我想传递一个像这样的热门目的地列表:

<popular>
    <country handle="india"/>
    <country handle="pakistan"/>
</popular>

...到/ countries模板,让它只对$ popular param中的那些进行操作。目前,这根本不起作用。将选择器更改为country [true()]对它们进行操作,所以至少我知道基本结构是正确的。

有什么想法吗?我想我可能会对目前的“当前()”感到困惑。

3 个答案:

答案 0 :(得分:2)

此问题的解决方案简单明了(无需字符串编码或递归)。

此转化:

<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:param name="pPopular">
    <country handle="india"/>
    <country handle="pakistan"/>
 </xsl:param>

 <xsl:variable name="vPopular" 
  select="document('')/*/xsl:param[@name='pPopular']"/>

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

 <xsl:template match="country">
  <xsl:if test="@handle = $vPopular/*/@handle">
   <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<countries>
    <country handle="bangladesh"/>
    <country handle="india"/>
    <country handle="pakistan"/>
</countries>

生成想要的正确结果

<countries>
    <country handle="india"/>
    <country handle="pakistan"/>
</countries>

答案 1 :(得分:1)

这比你想象的要简单得多:

<xsl:template match="/">
  <popular>
    <xsl:copy-of select="/countries/country[@handle=$popular/country/@handle]"/>
  </popular>
</xsl:template>

修改

上面简单地说明了OP的原始XPath查询有什么问题。这是一个完整的工作示例:

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

  <xsl:param name="popular"/>

  <xsl:template match="/">
      <xsl:apply-templates select="/countries">
        <xsl:with-param name="popular" select="$popular"/>
      </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="/countries">
    <xsl:param name="popular"/>
    <countries>
      <xsl:apply-templates select="country[@handle=$popular/country/@handle]"/>
    </countries>
  </xsl:template>

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

</xsl:stylesheet>

......以及一个叫它的程序:

static void Main(string[] arguments)
{
    XslCompiledTransform xslt = new XslCompiledTransform();
    xslt.Load("xsltfile1.xslt");

    XmlDocument d = new XmlDocument();
    d.LoadXml(@"
<popular>
  <country handle='india'/>
  <country handle='xxx'/>
</popular>");

    XsltArgumentList args = new XsltArgumentList();
    args.AddParam("popular", "", d.DocumentElement);
    xslt.Transform("xmlfile1.xml", args, Console.Out);
    Console.ReadKey();
}

答案 2 :(得分:0)

以下是使用递归模板的方法。您必须将热门目的地作为逗号分隔列表(例如:"'india,pakistan,'"

传递
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/countries">
    <xsl:param name="popular" select="'india,pakistan,'" />
    <xsl:for-each select="country">
        <xsl:call-template name="print-country-from-list">
      <xsl:with-param name="pc" select="."/>
      <xsl:with-param name="listc" select="$popular"/>
        </xsl:call-template>
    </xsl:for-each>
</xsl:template>

<xsl:template match="/countries/country">
   ... <xsl:value-of select="@handle"/>
</xsl:template>

<xsl:template name="print-country-from-list">
  <xsl:param name="pc"/>
  <xsl:param name="listc" select="''"/>
  <xsl:variable name="h" select="substring-before($listc, ',')"/>
  <xsl:if test="$h">
    <xsl:choose>
      <xsl:when test="$pc/@handle=$h">
        <xsl:apply-templates select="$pc" />
      </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="print-country-from-list">
        <xsl:with-param name="pc" select="$pc"/>
        <xsl:with-param name="listc" select="substring-after($listc, ',')"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

输出是2个国家。