2010-09-29 55 views
1

我有以下xml。在使用子串时忽略空格 - 在xsl后

<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是在看“安东尼”和“胡说”,并返回没什么作为的第一个空间是什么后“安东尼'之前,'布拉'之前。我怎样才能跳过第一空间并抓住'布拉'?

我使用XSLT 1.0,BTW。

谢谢!

+0

所以仅仅是明确的,你想'data2'是'Blah'? – 2010-09-29 15:27:56

回答

3

让我们通过你的步骤,因为它很清楚发生了什么以及如何解决它。

开始时你有以下字符串:"Smith Antony Blah Jones"

然后分配给变量querysubstring-before结果在第一个字符串。这分配"Smith"query

然后,您将query2分配为原始字符串的substring-aftersubstring-before的值。 substring-after返回"Antony Blah Jones"substring-before返回"Antony"。到现在为止还挺好。

现在你的下一个任务会在原始字符串"Antony",但那么你得到的字符串为" Blah Jones",所以当你运行substring-before,你匹配的第一个空格。

有很多可能的解决方案。调用substring-before,这样的前一个明显的人会打电话substring-after

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

但是,这是很丑陋的。或者,您可以使用substring或在您拨打第一个substring-after时拨打"Antony"

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

<xsl:template name="recursive-tokenizer"> 
    <xsl:param name="input"/> 
    <xsl:choose> 
    <!-- Test whether the input token contains a space. --> 
    <xsl:when test="contains($input,' ')"> 
     <!-- Output a token. --> 
     <xsl:value-of select="substring-before($input,' ')"/> 

     <!-- Call this template with the rest of the string. --> 
     <xsl:call-template name="recursive-tokenizer"> 
     <xsl:with-param name="input" select="substring-after($input,' ')"/> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <!-- There is no space, so just output the input. --> 
     <xsl:value-of select="$input"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
+0

+1为全面解答! – 2010-09-29 18:20:34

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后面加上一个空格。不是最干净的,但我认为它会工作...

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" /> 
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。

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>