Использование XSLT для поиска узлов с заданным набором параметров - PullRequest
2 голосов
/ 17 июня 2010

Извините за заголовок - не знаю, как его произнести.

В основном у меня есть такой 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>

… в шаблон / страны, и он будет работать только с теми в$ популярный параметр.На данный момент это просто ничего не делает.Изменение селектора на страну [true ()] действует на них всех, так что, по крайней мере, я знаю, что базовая структура верна.

Есть идеи?Я думаю, что меня может сбить с толку то, что в настоящее время называется current ().

Ответы [ 3 ]

2 голосов
/ 17 июня 2010

Решение этой проблемы простое и понятное (нет необходимости в кодировании строки или рекурсии).

Это преобразование:

<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 голос
/ 17 июня 2010

Это намного проще, чем вы думаете:

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

Редактировать

Выше было просто показано, что не так с исходным запросом XPath OP. Вот полный рабочий пример:

<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();
}
0 голосов
/ 17 июня 2010

Вот как вы можете это сделать с рекурсивным шаблоном.Вы должны передать популярные пункты назначения в виде списка через запятую (например: "'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 страны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...