Merge the values of multiple elements and take the average of the attribute field

£可爱£侵袭症+ 提交于 2019-12-11 03:44:38

问题


I need to merge the values of multiple elements and take the average of the attribute field.

[INPUT]

<xml>
   <characters>
       <char a="a1" b="b1" y="y1" z="z1"  start="1" weight="100">F</char>
       <char a="a2" b="b2" y="y2" z="z2"  start="0" weight="80">r</char>
       <char a="a3" b="b3" y="y3" z="z3"  start="0" weight="80">o</char>
       <char a="a4" b="b4" y="y4" z="z4"  start="0" weight="100">m</char>
       <char a="a5" b="b5" y="y5" z="z5"> </char>
       <char a="a6" b="b6" y="y6" z="z6"  start="1" weight="100">a</char>
       <char a="a7" b="b7" y="y7" z="z7"  start="0" weight="80">n</char>
       <char a="a8" b="b8" y="y8" z="z8"  start="0" weight="80">d</char>
       <char a="a9" b="b9" y="y9" z="z9"> </char>
   </characters>
</xml>

[OUTPUT]

<xml>
   <data>
       <word>
         <value>From</value>
         <coordinates>a1 b1 y4 z4</coordinates>
         <avgconfidence>90</avgconfidence>
        </word>

        <word>
            <value>and</value>
            <coordinates>a6 b6 y9 z9</coordinates>
            <avgconfidence>90</avgconfidence>
         </word>
  <data>
</xml>

I have written a partial XSL below by taking suggestion of @michael.hor257k in older thread . I did try with xsl:choose. it did not yield the expected result

[XSLT]

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />

    <xsl:template match="/">
        <data>
            <xsl:for-each select="characters">
               <word>
                    <value>
                        <xsl:for-each select="char">
                            <xsl:variable name="rec" select="." />
                            <xsl:if test="$rec/@start='1'">
                                <xsl:text>  <xsl:value-of select="$rec" /></xsl:text>
                            </xsl:if>
                        </xsl:for-each>
                    </value>

                     <coordinates>
            <xsl:value-of select="char[1]/@a"/>
            <xsl:text> </xsl:text>
            <xsl:value-of select="char[1]/@b"/>
            <xsl:text> </xsl:text>
            <xsl:value-of select="char[last()]/@y"/>
            <xsl:text> </xsl:text>
            <xsl:value-of select="char[last()]/@z"/>
        </coordinates>
                    <avgWeight>
                        <xsl:value-of select="sum(characters/char/@weight) div count(characters/char) "/>
                    </avgWeight>
                </word>

            </xsl:for-each>
        </data>
    </xsl:template>
</xsl:stylesheet>

Please help.


回答1:


Interesting problem - your partial XSL will work for a single word but you need a way to segment your characters into separate words and handle each word separately. I see it as a grouping task, where a "word" consists of a char[@start='1'] element along with its following char[@start='0'] elements. So you could approach it using a key to associate each non-word-initial char with the start of its word (i.e. its nearest preceding start='1' sibling)

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />

    <xsl:key name="wordChars" match="char[@start='0']"
             use="generate-id(preceding-sibling::char[@start='1'][1])" />

    <xsl:template match="/">
        <xml>
           <data>
               <xsl:apply-templates select="xml/characters/char[@start='1']" />
           </data>
        </xml>
    </xsl:template>

    <xsl:template match="char">
        <!-- all the chars in this word - . is the initial letter, the key gives the
             rest of the word -->
        <xsl:variable name="word" select=". | key('wordChars', generate-id())" />

        <word>
            <value>
                <xsl:for-each select="$word"><xsl:value-of select="."/></xsl:for-each>
            </value>
            <coordinates>
                <xsl:value-of select="concat(
                     $word[1]/@a, ' ', $word[1]/@b, ' ',
                     $word[last()]/@y, ' ', $word[last()]/@z)" />
            </coordinates>
            <avgconfidence>
                <xsl:value-of select="sum($word/@weight) div count($word)" />
            </avgconfidence>
        </word>
    </xsl:template>
</xsl:stylesheet>

When run over your sample input this produces

<xml>
  <data>
    <word>
      <value>From</value>
      <coordinates>a1 b1 y4 z4</coordinates>
      <avgconfidence>90</avgconfidence>
    </word>
    <word>
      <value>and</value>
      <coordinates>a6 b6 y8 z8</coordinates>
      <avgconfidence>86.6666666666667</avgconfidence>
    </word>
  </data>
</xml>

which I believe to be the correct answer (with end co-ordinates y8 z8 rather than y9 z9 and confidence 862/3 rather than 90 for the second word).



来源:https://stackoverflow.com/questions/27843380/merge-the-values-of-multiple-elements-and-take-the-average-of-the-attribute-fiel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!