XPath número de formato com o número de casas decimais com base em uma variável?
Pergunta
Eu tenho um documento XML onde o número de decimal coloca um xs:decimal
particular deve ser relatado na é realizada em um nó irmão. Atualmente estou lutando para encontrar uma maneira simples para a saída dessa via a função format-number
.
Eu posso construir uma seqüência de imagem com algumas outras funções, mas isso parece terrivelmente prolixo para o que deveria ser (pelo menos imo) uma tarefa relativamente simples e comum.
por exemplo. o que eu estou fazendo atualmente é algo como isto:
<xsl:value-of
select="format-number(myNode/DecimalValue,
concat('#0.',
string-join(for $i in 1 to myNode/DecimalPlaces return '0'))"
/>
Existe uma maneira melhor?
Solução
Muito boa pergunta! Isso normalmente significa, eu não sei a resposta, mas eu espero que alguém o faça, pois isso é uma dor para mim também.
De qualquer forma, eu fiz alguma pesquisa e eu acho que a função round-half-to-even
pode fazer o truque ( http://www.xqueryfunctions.com/xq/fn_round-half-to-even.html )
Seu código seria:
<xsl:value-of
select="
round-half-to-even(
myNode/DecimalValue
, myNode/DecimalPlaces
)
"
/>
Agora fora por um pouco de tangente: Para as pessoas que estão usando XSLT 1.1 ou inferior e XPath 1, você poderia usar o seguinte:
<xsl:value-of
select="
concat(
substring-before(DecimalValue, '.')
, '.'
, substring(substring-after(DecimalValue, '.'), 1, DecimalPlaces -1)
, round(
concat(
substring(substring-after(DecimalValue, '.'), DecimalPlaces, 1)
, '.'
, substring(substring-after(DecimalValue, '.'), DecimalPlaces+1)
)
)
)
"
/>
É claro, esse código é pior do que o original, mas se alguém sabe como resolver a questão original para XPath 1 e tem uma ideia melhor do que isso, eu adoraria ouvir isso. (Mais e mais frequentemente, eu desejo que o mundo teria XML totalmente ignorada e mudou-se imediatamente para JSON)
Outras dicas
<!-- use a generous amount of zeros in a top-level variable -->
<xsl:variable name="zeros" select="'000000000000000000000000000000000'" />
<!-- …time passes… -->
<xsl:value-of select="
format-number(
myNode/DecimalValue,
concat('#0.', substring($zeros, 1, myNode/DecimalPlaces))
)
" />
Você pode abstrair-lo em um template:
<!-- template mode is merely to prevent collisions with other templates -->
<xsl:template match="myNode" mode="FormatValue">
<xsl:value-of select="
format-number(
DecimalValue,
concat('#0.', substring($zeros, 1, DecimalPlaces))
)
" />
</xsl:template>
<!-- call like this -->
<xsl:apply-templates select="myNode" mode="FormatValue" />
Você também pode fazer um modelo chamado e usar o nó de contexto XSLT quando chamá-lo. Depende um pouco do seu documento de entrada e necessidades, se isso é viável para você.
<xsl:template name="FormatValue">
<!-- same as above -->
</xsl:template>
<!-- call like this -->
<xsl:for-each select="myNode">
<xsl:call-template name="FormatValue" />
</xsl:for-each>