2015-03-30 192 views
1

我想實現一個小整數評估器。實際上,它處理的xml文檔有一個表達式,以及包含可能變量值的varDef列表。XSLT整數求值器,如何實現n元和和乘法?

XSLT將該XML文檔轉換爲具有結果的另一個文檔。

這是XML文檔的XML模式:

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    xmlns:ej3="http://procesadores.ejemplo.com/Ej3" 
    targetNamespace="http://procesadores.ejemplo.com/Ej3" 
    elementFormDefault="qualified"> 

    <element name="documento"> 
     <complexType> 
      <sequence> 
       <element ref="ej3:expr"/> 
       <element ref="ej3:varDef" maxOccurs="unbounded" minOccurs="0"/> 
      </sequence> 
     </complexType> 
    </element> 

    <element name="expr" abstract="true"/> 

    <element name="suma" type="ej3:expBinaria" substitutionGroup="ej3:expr"/> 
    <element name="resta" type="ej3:expBinaria" substitutionGroup="ej3:expr"/> 
    <element name="mult" type="ej3:expBinaria" substitutionGroup="ej3:expr"/> 
    <element name="div" type="ej3:expBinaria" substitutionGroup="ej3:expr"/> 
    <element name="mod" type="ej3:expBinaria" substitutionGroup="ej3:expr"/> 
    <element name="opuesto" type="ej3:expUnaria" substitutionGroup="ej3:expr"/> 
    <element name="abs" type="ej3:expUnaria" substitutionGroup="ej3:expr"/> 

    <element name="var" type="ej3:tipoNombreVar" substitutionGroup="ej3:expr"/> 
    <element name="cons" type="integer" substitutionGroup="ej3:expr"/> 

    <element name="varDef"> 
     <complexType> 
      <simpleContent> 
       <extension base="int"> 
        <attribute name="nombre" type="ej3:tipoNombreVar"/> 
       </extension> 
      </simpleContent> 
     </complexType> 
    </element> 

    <complexType name="expUnaria"> 
     <sequence> 
      <element ref="ej3:expr" minOccurs="1" maxOccurs="1"/> 
     </sequence> 
    </complexType> 

    <complexType name="expBinaria"> 
     <sequence> 
      <element ref="ej3:expr" minOccurs="2" maxOccurs="2"/> 
     </sequence> 
    </complexType> 

    <complexType name="expNaria"> 
     <sequence> 
      <element ref="ej3:expr" minOccurs="0" maxOccurs="unbounded"/> 
     </sequence> 
    </complexType> 


    <simpleType name="tipoNombreVar"> 
     <restriction base="string"> 
      <pattern value="[a-zA-Z][a-zA-Z0-9]*"/> 
     </restriction> 
    </simpleType> 
</schema> 

這是XSLT文檔:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:ej3="http://procesadores.ejemplo.com/Ej3" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

    <xsl:strip-space elements="ej3:*"/> 

    <xsl:output 
     method="xml" 
     indent="yes" 
     encoding="utf-8"/> 

    <xsl:key name="defVariables" match="ej3:varDef" use="@nombre"/> 

    <xsl:template match="/ej3:documento"> 
     <cons><xsl:apply-templates select="*[not(local-name()='varDef')]"/></cons> 
    </xsl:template> 

    <xsl:template match="ej3:suma"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:variable name="s2"> 
      <xsl:apply-templates select="child::node()[2]"/> 
     </xsl:variable> 
     <xsl:value-of select="$s1 + $s2"/> 
    </xsl:template> 

    <xsl:template match="ej3:resta"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:variable name="s2"> 
      <xsl:apply-templates select="child::node()[2]"/> 
     </xsl:variable> 
     <xsl:value-of select="$s1 - $s2"/> 
    </xsl:template> 

    <xsl:template match="ej3:mult"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:variable name="s2"> 
      <xsl:apply-templates select="child::node()[2]"/> 
     </xsl:variable> 
     <xsl:value-of select="$s1 * $s2"/> 
    </xsl:template> 

    <xsl:template match="ej3:div"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:variable name="s2"> 
      <xsl:apply-templates select="child::node()[2]"/> 
     </xsl:variable> 

     <xsl:choose> 
      <xsl:when test="$s2 = 0"> 
       <xsl:value-of select="$s1 div $s2"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="xs:integer($s1 div $s2)"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template match="ej3:mod"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:variable name="s2"> 
      <xsl:apply-templates select="child::node()[2]"/> 
     </xsl:variable> 
     <xsl:value-of select="$s1 mod $s2"/> 
    </xsl:template> 

    <xsl:template match="ej3:opuesto"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:value-of select="- $s1"/> 
    </xsl:template> 

    <xsl:template match="ej3:abs"> 
     <xsl:variable name="s1"> 
      <xsl:apply-templates select="child::node()[1]"/> 
     </xsl:variable> 
     <xsl:value-of select="abs($s1)"/> 
    </xsl:template> 

    <xsl:template match="ej3:var"> 
     <xsl:value-of select="key('defVariables',.)"/> 
    </xsl:template>  

    <xsl:template match="ej3:cons"> 
     <test><xsl:value-of select="."/></test> 
    </xsl:template> 

</xsl:stylesheet> 

這是所有工作如我所料。但是我想讓suma(總計)和mult n-ary運營商。就是這樣的:

<suma> 
    <cons>1</cons> 
    <cons>2</cons> 
    <cons>3</cons> 
</suma> 

應該可以被評估。爲了這個工作,我必須修改suma xsl:模板,但我不太確定如何去做。我嘗試了許多事情,但事實上我必須在添加它們之前對孩子進行評估,這讓我很難找到解決方案。

你能提出如何實現這個嗎?

請注意,我希望summult操作數都能以此方式工作,因此基於xpath函數sum()的解決方案將不適用於mult

回答

2

我會確保您的模板返回xs:integer例如改變

<xsl:template match="ej3:cons"> 
    <test><xsl:value-of select="."/></test> 
</xsl:template> 

<xsl:template match="ej3:cons"> 
    <xsl:sequence select="xs:integer(.)"/> 
</xsl:template> 

那麼你可以使用

<xsl:template match="suma"> 
    <xsl:variable name="operands" as="xs:integer+"> 
    <xsl:apply-templates select="*"/> 
    </xsl:variable> 
    <xsl:sequence select="sum($operands)"/> 
</xsl:template> 

對於乘法,你可以使用一個函數(需要聲明綁定到其他命名空間的前綴mf

<xsl:function name="mf:multiply" as="xs:integer"> 
    <xsl:param name="operands" as="xs:integer+"/> 
    <xsl:sequence select="if (not(exists($operands[2]))) 
         then $operands[1] 
         else $operands[1] * mf:multiply($operands[position() gt 1])"/> 
</xsl:function> 

然後使用在

<xsl:template match="multa"> 
    <xsl:variable name="operands" as="xs:integer+"> 
    <xsl:apply-templates select="*"/> 
    </xsl:variable> 
    <xsl:sequence select="mf:multiply($operands)"/> 
</xsl:template> 

下面是一個例子:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:mf="http://example.com/mf" 
    exclude-result-prefixes="xs mf"> 

<xsl:output indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:function name="mf:multiply" as="xs:integer"> 
    <xsl:param name="operands" as="xs:integer+"/> 
    <xsl:sequence select="if (not(exists($operands[2]))) 
         then $operands[1] 
         else $operands[1] * mf:multiply($operands[position() gt 1])"/> 
</xsl:function> 

<xsl:template match="expression"> 
    <result> 
    <xsl:apply-templates/> 
    </result> 
</xsl:template> 

<xsl:template match="cons"> 
    <xsl:sequence select="xs:integer(.)"/> 
</xsl:template> 

<xsl:template match="suma"> 
    <xsl:variable name="operands" as="xs:integer+"> 
    <xsl:apply-templates select="*"/> 
    </xsl:variable> 
    <xsl:sequence select="sum($operands)"/> 
</xsl:template> 

<xsl:template match="multa"> 
    <xsl:variable name="operands" as="xs:integer+"> 
    <xsl:apply-templates select="*"/> 
    </xsl:variable> 
    <xsl:sequence select="mf:multiply($operands)"/> 
</xsl:template> 

</xsl:stylesheet> 

隨着例如輸入是

<expression> 
    <suma> 
    <cons>1</cons> 
    <cons>2</cons> 
    <cons>3</cons> 
    <multa> 
     <cons>1</cons> 
     <cons>2</cons> 
     <cons>3</cons> 
    </multa> 
    </suma> 
</expression> 

我得到的輸出<result>12</result>

+0

我怎麼能用這個aproach來實現n元乘法? – 2015-03-31 11:32:46

+0

@Trollkemada,我已經編輯了一些建議的答案,應該有助於實現它,雖然未經測試,只能直接在SO編輯器中輸入。 – 2015-03-31 11:44:46

+0

mult和sum將結果連接成一個字符串,這是我遇到的所有問題。我已經在一些在線xslt測試人員測試了相同的結果。 – 2015-03-31 13:51:51