2017-06-21 36 views
0

計算分割點鑑於以下XML輸入:XSLT/XML:如何動態地從一個輸入值

<shipment> 
    <goodsLines>FP-1|HP-0|QP-3|MQP-2</goodsLines> 
    <Barcodes>Code1|Code2|Code3|Code4|Code5|Code6</Barcodes> 
</shipment> 

和所需的輸出:

<Consignment> 
    <GoodsItemSet> 
     <GoodsItem goodsItemId="1"> 
      <NumberOfPackages unitCode="PCE">1</NumberOfPackages> 
      <PackageTypeCode>FP</PackageTypeCode> 
     </GoodsItem> 
     <Package packageId="Code1"/> 
    </GoodsItemSet> 
    <GoodsItemSet> 
     <GoodsItem goodsItemId="2"> 
      <NumberOfPackages unitCode="PCE">3</NumberOfPackages> 
      <PackageTypeCode>QP</PackageTypeCode> 
     </GoodsItem> 
     <Package packageId="Code2"/> 
     <Package packageId="Code3"/> 
     <Package packageId="Code4"/> 
    </GoodsItemSet> 
    <GoodsItemSet> 
     <GoodsItem goodsItemId="3"> 
      <NumberOfPackages unitCode="PCE">2</NumberOfPackages> 
      <PackageTypeCode>MQP</PackageTypeCode> 
     </GoodsItem> 
     <Package packageId="Code5"/> 
     <Package packageId="Code6"/> 
    </GoodsItemSet> 
</Consignment> 

的想法是遞歸分割管道,然後爲每個由管道分隔的GoodsLines值創建一個GoodsItemSet,其中包數=' - '之後的值。當值爲0時,我們不做任何事情。GoodsItemSet將具有1 .. *子包依賴於所述數字,並且ID將被順序提取:1. FP-1 => 1條碼,從1開始爲1. 2.QP-3 => 3條碼,從2到5等。條碼讀數的起始點將從'sum until now'開始+1。

如何在下面修改我的xslt,動態更改起點並將正確的條形碼與正確的GoodsItemSet配對?該解決方案將運行在Biztalk 2013R2(xslt1.0) 非常感謝。

我至今XSLT:

<xsl:template match="GoodsLines" name="GenerateGoodsItemSet"> 
    <xsl:param name="packagingCodes" select="."/> 
    <xsl:param name="unitsAccum" select="0"/> 
    <xsl:variable name="separator" select="'|'" /> 

    <xsl:variable name="headpackagingCode"> 
     <xsl:choose> 
      <xsl:when test="contains($packagingCodes, $separator)"> 
       <xsl:value-of select="substring-before($packagingCodes, $separator)"/> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$packagingCodes"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:variable> 

    <xsl:variable name="tailpackagingCodes" select="substring-after($packagingCodes, $separator)" /> 

    <xsl:if test="number(substring-after($headpackagingCode, '-')) &gt;0"> 
     <xsl:element name="GoodsItemSet"> 
      <xsl:element name="GoodsItem"> 
       <xsl:attribute name="goodsItemId"> 
        <xsl:number/> 
       </xsl:attribute> 
       <xsl:element name="NumberOfPackages"> 
        <xsl:attribute name="unitCode"> 
         <xsl:text>PCE</xsl:text> 
        </xsl:attribute> 
        <xsl:value-of select="substring-after($headpackagingCode, '-')"/> 
       </xsl:element> 

       <xsl:element name="PackageTypeCode"> 
        <xsl:value-of select="substring-before($headpackagingCode, '-')" /> 
       </xsl:element> 
      </xsl:element> 

      <!-- extract packageIds --> 
    <xsl:variable name="totalPackagesSoFar" select="substring-after($headpackagingCode, '-')"/> <!--Here I need a logic for the total processed so far, to use it as a starting point.--> 
      <xsl:choose> 
       <xsl:when test="position()=1"> 
        <xsl:apply-templates select="../Barcodes"> 
         <xsl:with-param name="start">1</xsl:with-param> 
         <xsl:with-param name="stop" select="number($unitsAccum + number(substring-after($headpackagingCode,'-')))"/> 
        </xsl:apply-templates> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:apply-templates select="../Barcodes"> 
         <xsl:with-param name="start" select="number($unitsAccum + $totalPackagesSoFar) +1"/> 
         <xsl:with-param name="stop" select="$unitsAccum + $totalPackagesSoFar + number(substring-after($headpackagingCode,'-'))"/> 
        </xsl:apply-templates> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:element> 
    </xsl:if> 

    <xsl:if test="$tailpackagingCodes"> 
     <xsl:call-template name="GenerateGoodsItemSet"> 
      <xsl:with-param name="packagingCodes" select="$tailpackagingCodes" /> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

<!--Tokenizer template--> 
    <xsl:template name="tokenize" match="Barcodes"> 
    <xsl:param name="text" select="."/> 
    <xsl:param name="separator" select="'|'"/> 
    <xsl:param name="pos" select="1"/> 
    <xsl:param name="start"/> 
    <xsl:param name="stop"/> 

    <xsl:choose> 
     <xsl:when test="not(contains($text, $separator))"> 
      <xsl:if test="$pos &gt;= $start and $pos &lt;= $stop"> 
       <xsl:element name="Package"> 
        <xsl:attribute name="packageId"> 
         <xsl:value-of select="normalize-space($text)"/> 
        </xsl:attribute> 
       </xsl:element> 
      </xsl:if> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:if test="$pos &gt;= $start and $pos &lt;= $stop"> 
       <xsl:element name="Package"> 
        <xsl:attribute name="packageId"> 
         <xsl:value-of select="normalize-space(substring-before($text, $separator))"/> 
        </xsl:attribute> 
       </xsl:element> 
      </xsl:if> 
      <xsl:call-template name="tokenize"> 
       <xsl:with-param name="text" select="substring-after($text, $separator)"/> 
       <xsl:with-param name="pos" select="$pos + 1"/> 
       <xsl:with-param name="start" select="$start"/> 
       <xsl:with-param name="stop" select="$stop"/> 
      </xsl:call-template> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
+0

這是一個可怕的很多工作。你在使用哪種XSLT處理器?你真的可以使用擴展函數的一些幫助。 –

+0

而不是從頭開始爲每個項目集選擇條形碼,而是將條形碼列表的相應尾部作爲模板參數傳遞,與您已經處理包裝代碼的方式類似。您可以使用單獨的遞歸模板來生成所需的尾部。 –

回答

0

這是難得一見的輸入XML這樣一個不友好的格式。我將接近這一問題的方法是通過重組投入的東西通過預處理兩個節點可行開始成類似:

<barcodes> 
    <token>Code1</token> 
    <token>Code2</token> 
    <token>Code3</token> 
    <token>Code4</token> 
    <token>Code5</token> 
    <token>Code6</token> 
</barcodes> 

<sets-rtf> 
    <set type="FP" qty="1"/> 
    <set type="HP" qty="0"/> 
    <set type="QP" qty="3"/> 
    <set type="MQP" qty="2"/> 
</sets-rtf> 

如果您的處理器支持EXSLT str:tokenize()擴展功能,這是相當容易的事情。否則,您將需要使用遞歸命名模板來生成此中間結果。

一旦你在上述形狀的輸入,事情變得更容易。下面是一個完整的樣式表:

XSLT 1.0(含EXSLT)

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common" 
xmlns:str="http://exslt.org/strings" 
extension-element-prefixes="exsl str"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<!-- pre-process barcodes --> 
<xsl:variable name="barcodes" select="str:tokenize(/shipment/Barcodes, '|')" /> 

<!-- pre-process sets --> 
<xsl:variable name="sets-rtf"> 
    <xsl:for-each select="str:tokenize(/shipment/goodsLines, '|')" > 
     <set type="{substring-before(., '-')}" qty="{substring-after(., '-')}"/> 
    </xsl:for-each> 
</xsl:variable> 

<!-- output--> 
<xsl:template match="/shipment"> 
    <Consignment> 
     <xsl:for-each select="exsl:node-set($sets-rtf)/set[@qty > 0]"> 
      <GoodsItemSet> 
       <GoodsItem goodsItemId="{position()}"> 
        <NumberOfPackages unitCode="PCE"> 
         <xsl:value-of select="@qty"/> 
        </NumberOfPackages> 
        <PackageTypeCode> 
         <xsl:value-of select="@type"/> 
        </PackageTypeCode> 
       </GoodsItem> 
       <xsl:call-template name="generate-packages"> 
        <xsl:with-param name="start" select="sum(preceding-sibling::set/@qty)"/> 
        <xsl:with-param name="qty" select="@qty"/> 
       </xsl:call-template>     
      </GoodsItemSet> 
     </xsl:for-each> 
    </Consignment> 
</xsl:template> 

<xsl:template name="generate-packages"> 
    <xsl:param name="start"/> 
    <xsl:param name="qty"/> 
    <xsl:if test="$qty > 0"> 
     <!-- recursive call --> 
     <xsl:call-template name="generate-packages"> 
      <xsl:with-param name="start" select="$start"/> 
      <xsl:with-param name="qty" select="$qty - 1"/> 
     </xsl:call-template> 
     <Package packageId="{$barcodes[$start + $qty]}"/> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 
+0

帽子@ michael.hor257k,你的建議很好用!我只需要使用msxsl node-set(),就像我的頭痛消失了一樣。你的男人:-) –

相關問題