2010-08-13 176 views
1

我正在尋找任何值才能在一個元件中設置類別ID的分隔列表...擁有所有選擇節點/列表

<Categories>851|849</Categories> 
<MatchType>any</MatchType> 

...,並利用它們的風格等元素.. 。

<Page CategoryIds="848|849|850|851">Page 1</Page> 
<Page CategoryIds="849|850|">Page 2</Page> 
<Page CategoryIds="848|850|">Page 3</Page> 
<Page CategoryIds="848|849|850|851">Page 4</Page> 
<Page CategoryIds="848|850|851">Page 5</Page> 
<Page CategoryIds="848|849|850">Page 6</Page> 

...根據他們是否不具備任何(或所有 ...取決於什麼在<MatchType>所示)給定的ID。

此外,ID不一定會按它們出現在CategoryIds屬性中的順序給出,並且該屬性內的字符串預計不會包含確切的<Categories>字符串。

是否可以使用XSLT/XPath 1.0?我知道2.0有一個令牌化功能,對此很適合,但不幸的是,我正在使用的CMS尚不支持2.0。

任何幫助將不勝感激!

+0

| | http://www.javapractices.com/topic/TopicAction.do?Id=96 – garik 2010-08-13 08:11:26

+0

符號化已在XSLT 1.0已經做了很多年,我想回答你的問題。唯一的問題是我完全*不知道你想實現什麼 - 請編輯你的問題並提供:1.源XML文檔(儘可能簡短)。 2.想要的結果。 3.解釋輸出的哪些部分必須根據輸入的哪些部分計算。 – 2010-08-13 12:43:48

+0

好吧,現在你有兩個解決方案 - 亞歷杭德羅和我的 - 都工作,都好。我終於明白你想要什麼(對於你將來的問題,你表達問題的方式很難理解),並根據我的(高)標準提出了一個我認爲很好的解決方案。如果解決方案中的某些內容不明確並接受其中一個,現在就由您來提問。而只是說「謝謝你的努力」。 – 2010-08-13 23:51:50

回答

0

雖然目前尚不清楚在所有來自這個問題你想做的事,這裏是一個答案,它的一部分:

是像這可能使用 XSLT/XPath 1.0中?我知道2.0有一個 令牌化功能,這將是 完美的,但不幸的是 我正在使用的CMS尚未 支持2.0。

令牌化已在XSLT 1.0中完成了很多年。儘管可以編寫自己的用於標記字符串的遞歸模板,但應該記住,FXSL庫中已經有了這樣一個解決方案,它可以保證工作,比典型的標記化實現更強大,並且不存在已知的錯誤 - 隨時可以使用。

這是str-split-to-words模板,這裏是用它的一個典型的例子:

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

    <xsl:import href="strSplit-to-Words.xsl"/> 

    <xsl:output indent="yes" omit-xml-declaration="yes"/> 

    <xsl:template match="/"> 
     <xsl:variable name="vwordNodes"> 
     <xsl:call-template name="str-split-to-words"> 
      <xsl:with-param name="pStr" select="/"/> 
      <xsl:with-param name="pDelimiters" 
          select="', &#9;&#10;&#13;'"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:apply-templates select="ext:node-set($vwordNodes)/*"/> 
    </xsl:template> 

    <xsl:template match="word"> 
     <xsl:value-of select="concat(position(), ' ', ., '&#10;')"/> 
    </xsl:template> 
</xsl:stylesheet> 

當這種轉變是在下面的XML文檔應用:

<t>Sorry, kid, first-borns really are smarter. 
First-borns are typically smarter, while 
younger siblings get better grades and 
are more outgoing, the researchers say</t> 

的想要,正確的結果產生

1 Sorry 
2 kid 
3 first-borns 
4 really 
5 are 
6 smarter. 
7 First-borns 
8 are 
9 typically 
10 smarter 
11 while 
12 younger 
13 siblings 
14 get 
15 better 
16 grades 
17 and 
18 are 
19 more 
20 outgoing 
21 the 
22 researchers 
23 say 

請注意該模板接受名爲pDelimiters的參數,其中可以指定多個分隔符。

更新:我終於明白了OP想要解決這個問題。這裏是我的解決方案,這再次使用str-split-to-words模板標記化:

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

    <xsl:import href="strSplit-to-Words.xsl"/> 

    <!-- to be applied upon: test-strSplit-to-Words2.xml --> 

    <xsl:output indent="yes" omit-xml-declaration="yes"/> 

    <xsl:template match="/"> 
     <xsl:variable name="vCategories"> 
     <xsl:call-template name="str-split-to-words"> 
      <xsl:with-param name="pStr" select= 
      "/*/select-criteria/Categories"/> 
      <xsl:with-param name="pDelimiters" 
          select="'|'"/> 
     </xsl:call-template> 
     </xsl:variable> 

     <xsl:apply-templates select="*/pages/Page"> 
     <xsl:with-param name="pCategories" select= 
     "ext:node-set($vCategories)"/> 
     <xsl:with-param name="pMatchType" select= 
     "*/select-criteria/MatchType"/> 
     </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="Page"> 
    <xsl:param name="pCategories"/> 
    <xsl:param name="pMatchType" select="any"/> 

    <xsl:variable name="vDecoratedCurrent" 
      select="concat('|', @CategoryIds, '|')"/> 

    <xsl:variable name="vSelected" select= 
     "$pCategories/* 
       [$pMatchType = 'any'] 
        [contains($vDecoratedCurrent, 
          concat('|', ., '|') 
          ) 
        ][1] 

     or 
     not($pCategories/*[not(contains($vDecoratedCurrent, 
             concat('|', ., '|') 
             ) 
           ) 
          ][1] 
      ) 
     "/> 

     <xsl:copy-of select="self::node()[$vSelected]"/> 
    </xsl:template> 
</xsl:stylesheet> 

當這一轉型是這個XML文檔的應用:

<t> 
<select-criteria> 
    <Categories>851|849</Categories> 
    <MatchType>any</MatchType> 
</select-criteria> 
<pages> 
    <Page CategoryIds="848|849|850|851">Page 1</Page> 
    <Page CategoryIds="849|850|">Page 2</Page> 
    <Page CategoryIds="848|850|">Page 3</Page> 
    <Page CategoryIds="848|849|850|851">Page 4</Page> 
    <Page CategoryIds="848|850|851">Page 5</Page> 
    <Page CategoryIds="848|849|850">Page 6</Page> 
</pages> 
</t> 

想要的,正確的結果產生

<Page CategoryIds="848|849|850|851">Page 1</Page> 
<Page CategoryIds="849|850|">Page 2</Page> 
<Page CategoryIds="848|849|850|851">Page 4</Page> 
<Page CategoryIds="848|850|851">Page 5</Page> 
<Page CategoryIds="848|849|850">Page 6</Page> 

W XML文檔中的母雞我們指定

<MatchType>all</MatchType> 

我們再次得到了想要的,正確的結果

<Page CategoryIds="848|849|850|851">Page 1</Page> 
<Page CategoryIds="848|849|850|851">Page 4</Page> 
+0

+1尼斯解決方案!這是如何做到這一點,當有可能通過擴展的方式標記在節點集中。很好。 – 2010-08-14 12:43:54

1

這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vMatch"> 
     <Categories>851|849</Categories> 
     <MatchType>any</MatchType> 
    </xsl:variable> 
    <xsl:param name="pMatch" select="document('')/*/xsl:variable[@name='vMatch']"/> 
    <xsl:template match="@*|node()" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="Page" name="page"> 
     <xsl:param name="pCategories" select="$pMatch/Categories"/> 
     <xsl:if test="$pCategories != ''"> 
      <xsl:variable name="vTest" select="contains(concat('|', 
                    @CategoryIds, 
                    '|'), 
                  concat('|', 
                    substring-before(concat($pCategories, 
                          '|'), 
                        '|'), 
                    '|'))"/> 
      <xsl:choose> 
       <xsl:when test="$vTest and ($pMatch/MatchType = 'any' or 
              substring-after($pCategories, 
                  '|') 
              = '')"> 
        <xsl:call-template name="identity"/> 
       </xsl:when> 
       <xsl:when test="($vTest and $pMatch/MatchType = 'all') or 
           $pMatch/MatchType = 'any' "> 
        <xsl:call-template name="page"> 
         <xsl:with-param name="pCategories" select="substring-after($pCategories,'|')"/> 
        </xsl:call-template> 
       </xsl:when> 
      </xsl:choose> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

白衣此輸入:

<Pages> 
    <Page CategoryIds="848|849|850|851">Page 1</Page> 
    <Page CategoryIds="849|850|">Page 2</Page> 
    <Page CategoryIds="848|850|">Page 3</Page> 
    <Page CategoryIds="848|849|850|851">Page 4</Page> 
    <Page CategoryIds="848|850|851">Page 5</Page> 
    <Page CategoryIds="848|849|850">Page 6</Page> 
</Pages> 

輸出:

<Pages> 
    <Page CategoryIds="848|849|850|851">Page 1</Page> 
    <Page CategoryIds="849|850|">Page 2</Page> 
    <Page CategoryIds="848|849|850|851">Page 4</Page> 
    <Page CategoryIds="848|850|851">Page 5</Page> 
    <Page CategoryIds="848|849|850">Page 6</Page> 
</Pages> 

注:因爲我不知道你在何處獲得Categories測試,我把那些內嵌在樣式表。這有一些優化:如果類別是發現和匹配類型是any或它的最後一類測試測試第一類,成功(調用模板identity),否則它使只有類別中找到了遞歸調用和匹配類型是all或之後未找到類別,匹配類型爲any。因此,它的成功與any「模式」的第一場比賽,並在all「模式」第一故障失敗。

編輯:只是爲了好玩,與Dimitre的輸入:

<t> 
<select-criteria> 
    <Categories>851|849</Categories> 
    <MatchType>all</MatchType> 
</select-criteria> 
<pages> 
    <Page CategoryIds="848|849|850|851">Page 1</Page> 
    <Page CategoryIds="849|850">Page 2</Page> 
    <Page CategoryIds="848|850">Page 3</Page> 
    <Page CategoryIds="848|849|850|851">Page 4</Page> 
    <Page CategoryIds="848|850|851">Page 5</Page> 
    <Page CategoryIds="848|849|850">Page 6</Page> 
</pages> 
</t> 

一號線的XPath 2.0

/t/*/Page[(
      /t/*/MatchType = 'any' 
        and 
      tokenize(/t/*/Categories,'\|') = tokenize(@CategoryIds,'\|') 
     ) or (
      /t/*/MatchType = 'all' 
        and 
      (every $x in tokenize(/t/*/Categories,'\|') 
      satisfies $x = tokenize(@CategoryIds,'\|')) 
     )] 

在XPath 2.1 let表達,那將是更簡潔.. 。

+0

@Alejandro:爲什麼這種複雜的努力產生與身份轉換相同的結果?你是如何確定OP真正想要的?請向我解釋這個謎。 :) – 2010-08-13 22:17:55

+0

@Dimitre:首先,因爲它很有趣。其次,它幾乎是契約轉換(缺少第3頁),但當然你已經看到了。用較少的努力,我用「pState」參數(對於「任何」初始爲假,對於「全部」初始爲真)隨每次遞歸而變化(或者 - 具有「任何」的邏輯和具有「全部」的邏輯) 。它很緊湊,但遍歷所有的令牌。花了我幾分鐘纔想出了這個優化版本。當然,我的過程並沒有做任何其他的應對......但是這是你的回答,吸引我回應! JA! – 2010-08-13 23:08:45

+0

@Alejandro:對不起,我沒有看到那麼小的差異。現在,我終於明白了OP想要什麼,並生成了一個解決方案,該解決方案在匹配條件中的類別標記化後使用單個XPath表達式。 – 2010-08-13 23:39:40