我需要在XForms表单中计算一个简单的加权平均值。如何使用XPath和/或XQuery以优雅和声明的方式实现?
[EDITED]这是源XML文档:
<Examens>
<Examen>
<ExamenId>1</ExamenId>
<Coef>1</Coef>
<Notes>
<Note>
<EleveId>100</EleveId>
<Valeur>4</Valeur>
</Note>
<Note>
<EleveId>101</EleveId>
<Valeur>4.2</Valeur>
</Note>
<Note>
<EleveId>102</EleveId>
<Valeur>3.8</Valeur>
</Note>
</Notes>
</Examen>
<Examen>
<ExamenId>2</ExamenId>
<Coef>2</Coef>
<Notes>
<Note>
<EleveId>100</EleveId>
<Valeur>5</Valeur>
</Note>
<Note>
<EleveId>101</EleveId>
<Valeur/>
</Note>
<Note>
<EleveId>102</EleveId>
<Valeur>3.5</Valeur>
</Note>
</Notes>
</Examen>
<Examen>
<ExamenId>3</ExamenId>
<Coef>3</Coef>
<Notes>
<Note>
<EleveId>100</EleveId>
<Valeur>6</Valeur>
</Note>
<Note>
<EleveId>101</EleveId>
<Valeur>5.4</Valeur>
</Note>
<Note>
<EleveId>102</EleveId>
<Valeur>2</Valeur>
</Note>
</Notes>
</Examen>
</Examens>
以下代码段正确显示了值(= ./Valeur
)和权重(= ./../../Coef
):
<xforms:repeat nodeset="$currentBranche//Note[EleveId=$currentEleveId]">
<xforms:output ref="./Valeur"/>
<xforms:output ref="./../../Coef"/>
</xforms:repeat>
BTW,我还需要排除Valeur
为空字符串的节点。例如,在以下使用XPath avg()
函数的简单平均计算中,如果一个节点的内容为空字符串,则会出现错误(“无法将'转换为''加倍”)。这是一个问题,因为节点存在(它是模型实例的一部分),当用户尚未输入值时,该值为空字符串。
<xforms:output ref="round(avg($currentBranche//Note[EleveId=$currentEleveId]/Valeur)*100) div 100"/>
[EDITED]
正确的计算是:
如果EleveId = 100:加权平均值=(1 * 4 + 2 * 5 + 3 * 6)/(1 + 2 + 3)= 5.333
如果EleveId = 101:加权平均值=(1 * 4.2 + 3 * 5.4)/(1 + 3)= 5.1
如果EleveId = 102:加权平均值=(1 * 3.8 + 2 * 3.5 + 3 * 2)/(1 + 2 + 3)= 2.8
答案 0 :(得分:2)
在XPath 1.0中使用:
sum($currentBranche//Note[EleveId=$currentEleveId]/Valeur[number(.)=number(.)])
div
count($currentBranche//Note[EleveId=$currentEleveId]/Valeur)
在Xpath 2.0(XQuery)中使用:
round(avg($currentBranche//Note[EleveId=$currentEleveId]/Valeur
[number(.)=number(.)])*100
) div 100
如果保证所有Valeur
值都可以投放为xs:decimal
,请使用:
avg($currentBranche//Note[EleveId=$currentEleveId]/Valeur
[castable as xs:decimal]
/xs:decimal(.)
)
在这种情况下,不会出现(明显的)精度损失,您可以稍后使用format-number()
函数来获得小数点后的所需位数。
<强> II。制作“加权平均值”:
鉴于提供的XML文档:
<Examens>
<Examen>
<ExamenId>1</ExamenId>
<Coef>1</Coef>
<Notes>
<Note>
<EleveId>100</EleveId>
<Valeur>4</Valeur>
</Note>
<Note>
<EleveId>101</EleveId>
<Valeur>4.2</Valeur>
</Note>
<Note>
<EleveId>102</EleveId>
<Valeur>3.8</Valeur>
</Note>
</Notes>
</Examen>
<Examen>
<ExamenId>2</ExamenId>
<Coef>2</Coef>
<Notes>
<Note>
<EleveId>100</EleveId>
<Valeur>5</Valeur>
</Note>
<Note>
<EleveId>101</EleveId>
<Valeur/>
</Note>
<Note>
<EleveId>102</EleveId>
<Valeur>3.5</Valeur>
</Note>
</Notes>
</Examen>
<Examen>
<ExamenId>3</ExamenId>
<Coef>3</Coef>
<Notes>
<Note>
<EleveId>100</EleveId>
<Valeur>6</Valeur>
</Note>
<Note>
<EleveId>101</EleveId>
<Valeur>5.4</Valeur>
</Note>
<Note>
<EleveId>102</EleveId>
<Valeur>2</Valeur>
</Note>
</Notes>
</Examen>
</Examens>
此XPath 2.0表达式产生加权平均值:
for $elevId in distinct-values(/*/*/*/*/EleveId)
return
round(100*
(sum(/*/*/*/Note
[EleveId eq $elevId
and number(Valeur) eq number(Valeur)
]
/(Valeur * ../../Coef)
)
div
sum(/*/*/*/Note
[EleveId eq $elevId
and number(Valeur) eq number(Valeur)
]
/../../Coef
)
)
)
div 100
并生成预期的正确结果:
5.33 5.1 2.8