使用 XPATH 1.0 添加两个 hexBinary

发布于 2024-09-06 00:18:13 字数 1115 浏览 2 评论 0原文

我的 xml 文档看起来有点像这样(值都是 xsl:hexBinary):

<Offsets>  
    <Offset>  
        <Name>ErrorOffset</Name>  
        <Value>DD</Value>  
    </Offset>  
    <Offset>  
        <Name>OtherOffset</Name>  
        <Value>FF</Value>  
    </Offset>  
</Offsets>  
<Value>  
    <Name>Error1</Name>  
    <Code>01</Code>  
</Value>
<Value>  
    <Name>Error2</Name>  
    <Code>02</Code>  
    <Offset>ErrorOffset</Offset>  
</Value>

现在我想将其转换为新的 xml 文件:

<Value>  
    <Name>Error1</Name>  
    <Code>01</Code>  
</Value>
<Value>  
    <Name>Error2</Name>  
    <Code>DF</Code>  
</Value>

应该发生的就是添加 到基本的 。但普通的 + 返回 NaN 并且 sum() 只需要一个参数。 XSLT 和 XPATH 非常好,但让我感到不安的是,像添加两个十六进制值这样的简单操作并不像应有的那么简单。

my xml document looks somewhat like that (Values are both xsl:hexBinary):

<Offsets>  
    <Offset>  
        <Name>ErrorOffset</Name>  
        <Value>DD</Value>  
    </Offset>  
    <Offset>  
        <Name>OtherOffset</Name>  
        <Value>FF</Value>  
    </Offset>  
</Offsets>  
<Value>  
    <Name>Error1</Name>  
    <Code>01</Code>  
</Value>
<Value>  
    <Name>Error2</Name>  
    <Code>02</Code>  
    <Offset>ErrorOffset</Offset>  
</Value>

now i want to transform this to a new xml file:

<Value>  
    <Name>Error1</Name>  
    <Code>01</Code>  
</Value>
<Value>  
    <Name>Error2</Name>  
    <Code>DF</Code>  
</Value>

All that should happen is adding <Offset> to the basic <Value>. But plain + returns NaN and sum() expects only one parameter. XSLT and XPATH are quite nice, but it goes on my nerves that easy operations like adding two hex values just dont work as easy as it should.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不乱于心 2024-09-13 00:18:14

我从未开发过十六进制数字的转换函数。这是与 Dimitre 示例相反的函数示例。我认为可以进一步减少样式表。还值得注意的是,转换函数可以参数化并推广到任何基数。

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

<xsl:key name="offset" match="Offset/Value" use="../Name" />     

<xsl:template match="@*|node()"> 
    <xsl:copy> 
        <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="Offsets|Offset" />

<xsl:template match="Code/text()[../../Offset]" >
    <xsl:variable name="code">
        <xsl:call-template name="hex2dec">
            <xsl:with-param name="num" select="." />
        </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="offset">
        <xsl:call-template name="hex2dec">
            <xsl:with-param name="num" select="key('offset',../../Offset)" />
        </xsl:call-template>
    </xsl:variable>
    <xsl:call-template name="dec2hex">
        <xsl:with-param name="dec" select="$code + $offset" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="hex2dec">
    <xsl:param name="num" />
    <xsl:param name="hex" select="translate($num,'abcdef','ABCDEF')"/>
    <xsl:param name="acc" select="0" />
    <xsl:choose>
        <xsl:when test="string-length($hex)">
            <xsl:call-template name="hex2dec">
                <xsl:with-param name="hex" select="substring($hex,2,string-length($hex))" />
                <xsl:with-param name="acc" select="$acc * 16 + string-length(substring-before('0123456789ABCDEF',substring($hex,1,1)))" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$acc" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="dec2hex">
    <xsl:param name="dec" />
    <xsl:if test="$dec >= 16">
        <xsl:call-template name="dec2hex">
            <xsl:with-param name="dec" select="floor($dec div 16)" />
        </xsl:call-template>
    </xsl:if>
    <xsl:value-of select="substring('0123456789ABCDEF', ($dec mod 16) + 1, 1)" />
</xsl:template>

</xsl:stylesheet> 

编辑:最近我刚刚意识到这里是交叉引用。因此应该使用键。

I never developed a conersión function for hex numbers. This is an example of a function that is reverse to the example of Dimitre. I think it would be possible to further reduce the stylesheet. It is also worth noting that the conversion function can be parameterized and generalized to any base.

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

<xsl:key name="offset" match="Offset/Value" use="../Name" />     

<xsl:template match="@*|node()"> 
    <xsl:copy> 
        <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="Offsets|Offset" />

<xsl:template match="Code/text()[../../Offset]" >
    <xsl:variable name="code">
        <xsl:call-template name="hex2dec">
            <xsl:with-param name="num" select="." />
        </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="offset">
        <xsl:call-template name="hex2dec">
            <xsl:with-param name="num" select="key('offset',../../Offset)" />
        </xsl:call-template>
    </xsl:variable>
    <xsl:call-template name="dec2hex">
        <xsl:with-param name="dec" select="$code + $offset" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="hex2dec">
    <xsl:param name="num" />
    <xsl:param name="hex" select="translate($num,'abcdef','ABCDEF')"/>
    <xsl:param name="acc" select="0" />
    <xsl:choose>
        <xsl:when test="string-length($hex)">
            <xsl:call-template name="hex2dec">
                <xsl:with-param name="hex" select="substring($hex,2,string-length($hex))" />
                <xsl:with-param name="acc" select="$acc * 16 + string-length(substring-before('0123456789ABCDEF',substring($hex,1,1)))" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$acc" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="dec2hex">
    <xsl:param name="dec" />
    <xsl:if test="$dec >= 16">
        <xsl:call-template name="dec2hex">
            <xsl:with-param name="dec" select="floor($dec div 16)" />
        </xsl:call-template>
    </xsl:if>
    <xsl:value-of select="substring('0123456789ABCDEF', ($dec mod 16) + 1, 1)" />
</xsl:template>

</xsl:stylesheet> 

Edit: Recently I just realized here is cross references. Therefore keys should be used.

风吹过旳痕迹 2024-09-13 00:18:14

这是一个解决方案,它结合了 FXSL 中存在的十六进制到十进制值的转换 使用借用的非 FXSL 模板 用于将十进制转换为十六进制。

此转换

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:func-transform2="f:func-transform2"
exclude-result-prefixes="xsl f func-transform2"
>
   <xsl:import href="transform-and-sum.xsl"/>
   <xsl:import href="hex-to-decimal.xsl"/>

   <!-- to be applied on testTransform-and-sum2.xml -->

   <xsl:output method="text"/>

   <func-transform2:func-transform2/>

    <xsl:template match="/">
      <xsl:variable name="vdecSum">
       <xsl:call-template name="transform-and-sum">
        <xsl:with-param name="pFuncTransform" 
                        select="document('')/*/func-transform2:*[1]"/>
        <xsl:with-param name="pList" select="/*/*"/>
       </xsl:call-template>
      </xsl:variable>

      <xsl:call-template name="toHex">
       <xsl:with-param name="decimalNumber" select="$vdecSum"/>
      </xsl:call-template>

    </xsl:template>

    <xsl:template match="func-transform2:*" mode="f:FXSL">
      <xsl:param name="arg1" select="0"/>

      <xsl:call-template name="hex-to-decimal">
        <xsl:with-param name="pxNumber" select="$arg1"/>
      </xsl:call-template>
    </xsl:template>

  <xsl:template name="toHex">
    <xsl:param name="decimalNumber" />
    <xsl:if test="$decimalNumber >= 16">
      <xsl:call-template name="toHex">
        <xsl:with-param name="decimalNumber" select="floor($decimalNumber div 16)" />
      </xsl:call-template>
    </xsl:if>
    <xsl:value-of select="substring($hexDigits, ($decimalNumber mod 16) + 1, 1)" />
</xsl:template>

</xsl:stylesheet>

应用于此 XML 文档时

<t>
 <hexNum>1001</hexNum>
 <hexNum>0FA3</hexNum>
</t>

产生正确的所需结果

1FA4

Here is a solution, which combines the conversion of hex to decimal values as present in FXSL with a borrowed non-FXSL template for convertion of decimal to hex.

This transformation:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:func-transform2="f:func-transform2"
exclude-result-prefixes="xsl f func-transform2"
>
   <xsl:import href="transform-and-sum.xsl"/>
   <xsl:import href="hex-to-decimal.xsl"/>

   <!-- to be applied on testTransform-and-sum2.xml -->

   <xsl:output method="text"/>

   <func-transform2:func-transform2/>

    <xsl:template match="/">
      <xsl:variable name="vdecSum">
       <xsl:call-template name="transform-and-sum">
        <xsl:with-param name="pFuncTransform" 
                        select="document('')/*/func-transform2:*[1]"/>
        <xsl:with-param name="pList" select="/*/*"/>
       </xsl:call-template>
      </xsl:variable>

      <xsl:call-template name="toHex">
       <xsl:with-param name="decimalNumber" select="$vdecSum"/>
      </xsl:call-template>

    </xsl:template>

    <xsl:template match="func-transform2:*" mode="f:FXSL">
      <xsl:param name="arg1" select="0"/>

      <xsl:call-template name="hex-to-decimal">
        <xsl:with-param name="pxNumber" select="$arg1"/>
      </xsl:call-template>
    </xsl:template>

  <xsl:template name="toHex">
    <xsl:param name="decimalNumber" />
    <xsl:if test="$decimalNumber >= 16">
      <xsl:call-template name="toHex">
        <xsl:with-param name="decimalNumber" select="floor($decimalNumber div 16)" />
      </xsl:call-template>
    </xsl:if>
    <xsl:value-of select="substring($hexDigits, ($decimalNumber mod 16) + 1, 1)" />
</xsl:template>

</xsl:stylesheet>

when applied on this XML document:

<t>
 <hexNum>1001</hexNum>
 <hexNum>0FA3</hexNum>
</t>

produces the correct, wanted result:

1FA4
那小子欠揍 2024-09-13 00:18:14

这就是我在不使用 XSLT 的情况下执行此操作的方法:

十六进制到数字

160 * translate(substring(Offsets/Offset/Value,1,1),
                  '0123456789ABCDEFabcdef',
                  '0000000000111111111111')         +
16 * translate(substring(Offsets/Offset/Value,1,1),
                  '0123456789ABCDEFabcdef',
                  '0123456789012345012345')         +
10 * translate(substring(Offsets/Offset/Value,2,1),
                  '0123456789ABCDEFabcdef',
                  '0000000000111111111111')         +
translate(substring(Offsets/Offset/Value,2,1),
                  '0123456789ABCDEFabcdef',
                  '0123456789012345012345')

反向函数更简单:

concat(
  substring('0123456789ABCDEF', valueDecimal   / 16 ,1)  ,
  substring('0123456789ABCDEF', valueDecimal mod 16 ,1) 
)

两者都假设您的十六进制数字始终有两位数字。

This is how I do it without using XSLT:

Hex to number

160 * translate(substring(Offsets/Offset/Value,1,1),
                  '0123456789ABCDEFabcdef',
                  '0000000000111111111111')         +
16 * translate(substring(Offsets/Offset/Value,1,1),
                  '0123456789ABCDEFabcdef',
                  '0123456789012345012345')         +
10 * translate(substring(Offsets/Offset/Value,2,1),
                  '0123456789ABCDEFabcdef',
                  '0000000000111111111111')         +
translate(substring(Offsets/Offset/Value,2,1),
                  '0123456789ABCDEFabcdef',
                  '0123456789012345012345')

The reverse function is simpler:

concat(
  substring('0123456789ABCDEF', valueDecimal   / 16 ,1)  ,
  substring('0123456789ABCDEF', valueDecimal mod 16 ,1) 
)

Both assume your hex digits always have two digits.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文