在xsl中使用substring-after时忽略空格

时间:2010-09-29 15:21:06

标签: xml xslt substring

我有以下xml。

<root query="Smith Antony Blah Jones">

以下xsl将字符串拆分为不同的变量。

<xsl:variable name="query">
<xsl:value-of select="substring-before (root/@query, ' ')" />
</xsl:variable>

<xsl:variable name="query1">
<xsl:value-of select="substring-before(substring-after(root/@query, ' '), ' ')" />
</xsl:variable>

<xsl:variable name="query2"><xsl:value-of select="substring-before(substring-after(root/@query, $query1), ' ')"/></xsl:variable>

<xsl:template match="root">
<search data="{$query}" data1="{$query1}" data2="{$query2}" "/>

但是我得到以下html

<search data="Smith" data1="Antony" data2="" data3=""/>

我可以看到xsl在查看'Antony'和'Blah'之间的第一个空格并且没有返回任何内容,因为这是'Antony'之后和'Blah'之前的内容。如何跳过第一个空格并捕获'Blah'?

我正在使用XSLT 1.0,BTW。

谢谢!

5 个答案:

答案 0 :(得分:3)

让我们完成您的步骤,因为它非常清楚发生了什么以及如何解决它。

您可以从以下字符串开始:"Smith Antony Blah Jones"

然后在第一个字符串上为变量query分配substring-before的结果。这会将"Smith"分配给query

然后,您为query2分配原始字符串substring-before的{​​{1}}值。 substring-after返回substring-after"Antony Blah Jones"返回substring-before。到目前为止一切都很好。

现在,您的下一个作业会在原始字符串中查找"Antony",但结果字符串为"Antony",因此当您运行" Blah Jones"时,您将匹配第一个空格。

有很多可能的解决方案。显而易见的是在调用substring-before之前调用substring-after,如下所示:

substring-before

但那很难看。或者,当您进行第一次<xsl:value-of select="substring-before(substring-after(substring-after(root/@query, $query1), ' '),' ')" /> 来电时,您可以使用substring或仅使用空格"Antony"

我认为你最好定义一个递归模板来获取下一个标记然后将剩余的字符串传递给它自己。这将允许您从字符串中获取任意数量的以空格分隔的标记,而不必拥有如此多的编号变量。像这样:

substring-after

答案 1 :(得分:0)

你能改变这一行:

<xsl:variable name="query2"><xsl:value-of select="substring-before(substring-after(root/@query, $query1), ' ')"/></xsl:variable>

到此:

<xsl:variable name="query2"><xsl:value-of select="substring-before(concat(substring-after(root/@query, $query1),' '), ' ')"/></xsl:variable>

只需在$query1的末尾添加空格即可。不是最干净但我认为它会起作用......

答案 2 :(得分:0)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="root">
        <search>
            <xsl:call-template name="query"/>
        </search>
    </xsl:template>
    <xsl:template name="query">
        <xsl:param name="pString" select="@query"/>
        <xsl:param name="pNumber" select="0"/>
        <xsl:param name="pTop" select="3"/>
        <xsl:choose>
            <xsl:when test="$pNumber > $pTop"/>
            <xsl:when test="contains($pString,' ')">
                <xsl:call-template name="query">
                    <xsl:with-param name="pString" 
                                    select="substring-before($pString,' ')"/>
                    <xsl:with-param name="pNumber" select="$pNumber"/>
                    <xsl:with-param name="pTop" select="$pTop"/>
                </xsl:call-template>
                <xsl:call-template name="query">
                    <xsl:with-param name="pString" 
                                    select="substring-after($pString,' ')"/>
                    <xsl:with-param name="pNumber" select="$pNumber + 1"/>
                    <xsl:with-param name="pTop" select="$pTop"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:attribute 
                     name="data{substring($pNumber, 1 div ($pNumber != 0))}">
                    <xsl:value-of select="$pString"/>
                </xsl:attribute>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

使用此输入:

<root query="Smith Antony Blah Jones"/>

输出:

<search data="Smith" data1="Antony" data2="Blah" data3="Jones" />

答案 3 :(得分:0)

您真正要问的是,“我如何使用XSLT来解析字符串?”虽然这个可以完成(Alejandro提出的递归方法很好),但预处理这样的文档通常要简单得多,使用比XSLT更好的字符串操作语言来解析字符串,并且在转换文档之前修改文档。

例如,在C#中,您可以编写一个这样的简单方法:

foreach (XmlElement elm in doc.SelectNodes("//*[@query]"))
{
   foreach (string s in elm.GetAttribute("@query")
      .Split(new[] {' '})
      .Where(x => !(string.IsNullOrEmpty(x))))
   {
      XmlElement query = doc.CreateElement("query")
      query.InnerText = s;
      elm.AppendChild(query);
   }
}

现在您的元素将如下所示:

<root query="Antony Blah Smith Jones">
   <query>Antony</query>
   <query>Blah</query>
   <query>Smith</query>
   <query>Jones</query>
</root>

在XSLT中访问这些子字符串元素很简单。

答案 4 :(得分:0)

如果您使用的是XSLT 2,那么您可以这样做:

<search>
  <xsl:for-each select="tokenize(/root/@query,'\s+')">
    <xsl:attribute name="data{(position() - 1)[. &gt; 0]}"
                   select="."/>
  </xsl:for-each>
</search>