2010-09-29 31 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>