Using XSLT, how do I increase the value of the 

2019-08-02 15:38发布

There are 2321 occurrences of the character 'a' in the element contents of my source XML file.

I have succeeded in obtaining this number, but I can only do it for the 'a' character. I need to obtain the occurrences for all the letters of the alphabet.

See code:

This is used to print out a TextBlock element:

<xsl:template name="get-textblock">

    <xsl:param name="letter-one"/>
    <xsl:param name="letter-two"/>
    <xsl:param name="letter-one-f"/>
    <xsl:param name="letter-two-f"/>

    <xsl:if test="$letter-one">
        <xsl:number value="$letter-one" format="$letter-one-f"/>
    </xsl:if>

    <xsl:if test="$letter-two">
        <xsl:number value="$letter-two" format="$letter-two-f"/>
    </xsl:if>

</xsl:template>

Then, in this recursive loop I print out how many times 'a' or 'A' occur, using an XPath expression and the get-textblock template.

<xsl:template name="print-alphabet-value-rows">
    <!-- 'letter' is just a counter. -->
    <xsl:param name="letter" select="1"/>
    <!-- numbers -->
    <xsl:param name="letter-one" select="1"/>
    <xsl:param name="letter-two" select="1"/>
    <!-- format attribute values -->
    <xsl:param name="letter-one-f" select=" 'a' "/>
    <xsl:param name="letter-two-f" select=" 'A' "/>
    <xsl:param name="gridrow">2</xsl:param>
    <xsl:param name="gridcol">2</xsl:param>

    <xsl:call-template name="get-textblock">
        <xsl:with-param name="gridrow" select="$gridrow"/>
        <xsl:with-param name="gridcol" select="$gridcol"/>
        <xsl:with-param name="style">{StaticResource ValueText}</xsl:with-param>
        <xsl:with-param name="letter-one-f" select="$letter-one-f"/>
        <xsl:with-param name="letter-two-f" select="$letter-two-f"/>
        <xsl:with-param name="letter-one" select="$letter-one"/>
        <xsl:with-param name="letter-two" select="$letter-two"/>
        <xsl:with-param name="text">
            <xsl:value-of select="count(/n-grams-sorted/n-gram[starts-with(.,$letter-one-f) or starts-with(.,$letter-two-f) ])"/>
        </xsl:with-param>
    </xsl:call-template>

    <xsl:if test="$letter &lt; 26">
        <xsl:call-template name="print-alphabet-value-rows">
            <xsl:with-param name="gridrow" select="$gridrow + 1"/>
            <xsl:with-param name="letter" select="$letter +1"/>
            <!-- this doesn't work. It prints out the same number of occurrences for all the rows because it only fetches 'a' and 'A', it never increases them -->
            <xsl:with-param name="letter-one" select="$letter-one +1"/>
            <xsl:with-param name="letter-two" select="$letter-two +1"/>
        </xsl:call-template>
    </xsl:if>

So, what I do here is I define a get-textblock template to draw a TextBlock element. Then, I supply the following parameters:

letter: a counter to simply go 26 rows down

letter-one: a number which has a format 'a' attached to it

letter-two: a number which has a format 'A' attached to it

What I want to do is keep increasing 'a' and 'A', so that the corresponding XPath expression reads 'b' & 'B', 'c' & 'C' etc., all the way down to the last letter of the alphabet. I don't know to accomplish that.

Any ideas? Thanks

3条回答
女痞
2楼-- · 2019-08-02 16:02

Here is another XSLT 1.0 way of doing this:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:variable name="vLower" select=
  "'abcdefghijklmnopqrstuvwxyz'"/>

 <xsl:variable name="vUpper" select=
  "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>

 <xsl:variable name="vDoc" select="document('')"/>

 <xsl:template match="/">
   <xsl:for-each select=
    "($vDoc//node() | $vDoc//@* |$vDoc//namespace::*)
           [not(position() > 25)]
    ">
    <xsl:variable name="vPos" select="position()"/>

    <xsl:variable name="vcurLow" select=
    "substring($vLower,$vPos, 1)"/>

    <xsl:value-of select="concat($vcurLow, ' --> ')"/>

    <xsl:call-template name="incrementLetter">
      <xsl:with-param name="pLetter" select="$vcurLow"/>
      <xsl:with-param name="pAlha" select="$vLower"/>
    </xsl:call-template>
    <xsl:text>&#xA;</xsl:text>
   </xsl:for-each>
 </xsl:template>

 <xsl:template name="incrementLetter">
   <xsl:param name="pLetter"/>
   <xsl:param name="pAlha"/>

   <xsl:value-of select=
"substring($pAlha,
       string-length(substring-before($pAlha,$pLetter))+2,
           1)"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on any XML document (not used), the result shows that any letter is incremented correctly:

a --> b
b --> c
c --> d
d --> e
e --> f
f --> g
g --> h
h --> i
i --> j
j --> k
k --> l
l --> m
m --> n
n --> o
o --> p
p --> q
q --> r
r --> s
s --> t
t --> u
u --> v
v --> w
w --> x
x --> y
y --> z
查看更多
Anthone
3楼-- · 2019-08-02 16:03

I'm not totally sure I understand the question, but can you do anything with something like

translate($letter-one, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ','bcdefghijklmnopqrstuvwxyzaBCDEFGHIJKLMNOPQRSTUVWXYZA')
查看更多
在下西门庆
4楼-- · 2019-08-02 16:16

You haven't said whether this is XSLT 1.0 or 2.0, but I assume it's 1.0 because otherwise the problem would be pretty trivial. But even in XSLT 1.0, it seems straightforward enough if you're prepared to write the alphabet out as a string. (I assume by 'alphabet' you mean the English alphabet of 26 letters.)

查看更多
登录 后发表回答