代码之家  ›  专栏  ›  技术社区  ›  atamanroman

添加两个具有xpath 1.0的十六进制

  •  1
  • atamanroman  · 技术社区  · 15 年前

    我的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>
    

    只会增加 <Offset> 基本 <Value> . 但是平原 + 收益率 NaN sum() 只需要一个参数。xslt和xpath非常好,但我担心,像添加两个十六进制值这样的简单操作并不像它应该的那么简单。

    3 回复  |  直到 11 年前
        1
  •  1
  •   user357812    15 年前

    我从未为十六进制数开发过conersi_3 n函数。这是与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> 
    

    编辑: 最近我才发现这里是交叉引用。因此,应使用钥匙。

        2
  •  1
  •   Dimitre Novatchev    15 年前

    这是一个解决方案 ,它结合了十六进制到十进制值的转换,如 FXSL 用一个 borrowed non-FXSL template 用于十进制到十六进制的转换。

    这种转变 :

    <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
    
        3
  •  0
  •   Stavr00    11 年前

    这就是我不使用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) 
    )
    

    两者都假定十六进制数字总是有两个数字。