XSLT 1.0 : 需要对具有父ID的元素进行分组。

问题描述 投票:0回答:1

我需要把Parentsscc和它的Logisticsscc联系起来,我们需要在输入文件中检查相同的Parentsscc&需要把它和它的logisticsscc联系起来,结果输出必须是logisticsscc和它的parentsscc.我提供了输入和输出的细节。新代码不复制Parentsscc与它的logistic sscc。

输入:

<?xml version="1.0" encoding="UTF-8"?>
<wONM>
   <Standard>
      <Sender>1</Sender>                
   </Standard>
   <warehousingNotification>      
      <warehousingIdentification>
         <entityIdentification>000031115</entityIdentification>
      </warehousingIdentification>
      <warehousingOperationsTransaction>
        <SNumber>1</SNumber>
         <warehousingOperationsLocation>
            <inventoryLocation>        
            </inventoryLocation>
            <logistic>
               <sscc>101</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>190</sscc>
               <parent>
                  <sscc>204</sscc>
               </parent>              
            </logistic>
            <logistic>
               <sscc>102</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>191</sscc>
               <parent>
                  <sscc>204</sscc>
               </parent>               
            </logistic>
         </warehousingOperationsLocation>
      </warehousingOperationsTransaction>
      <warehousingOperationsTransaction>
        <SNumber>2</SNumber>
         <warehousingOperationsLocation>
            <inventoryLocation>
            </inventoryLocation>
            <logistic>
               <sscc>192</sscc>
               <parent>
                  <sscc>204</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>107</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>197</sscc>
               <parent>
                  <sscc>204</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>108</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>               
            </logistic>
         </warehousingOperationsLocation>
      </warehousingOperationsTransaction>
      <warehousingOperationsTransaction>
         <SNumber>3</SNumber>
         <warehousingOperationsLocation>
            <inventoryLocation>
            </inventoryLocation>
            <logistic>
               <sscc>101</sscc>
               <parent>
                  <sscc>205</sscc>
               </parent>              
            </logistic>
            <logistic>
               <sscc>102</sscc>
               <parent>
                  <sscc>206</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>109</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>              
            </logistic>
            <logistic>
               <sscc>110</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>               
            </logistic>
         </warehousingOperationsLocation>
      </warehousingOperationsTransaction>
   </warehousingNotification>
</wONM>

輸出。

<?xml version="1.0" encoding="UTF-8"?>
<wONM>
   <Standard>
      <Sender>1</Sender>                
   </Standard>
   <warehousingNotification>      
       <warehousingIdentification>
         <entityIdentification>000031115</entityIdentification>
      </warehousingIdentification>
      <warehousingOperationsTransaction>
        <SNumber>1</SNumber>
         <warehousingOperationsLocation>
            <inventoryLocation>        
            </inventoryLocation>
            <logistic>
               <sscc>101</sscc>
               <sscc>102</sscc>
               <sscc>107</sscc>
               <sscc>108</sscc>
               <sscc>109</sscc>
               <sscc>110</sscc>
               <parent>
                  <sscc>203</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>190</sscc>
               <sscc>191</sscc>
               <sscc>192</sscc>
               <sscc>197</sscc>
               <parent>
                  <sscc>204</sscc>
               </parent>              
            </logistic>
            <logistic>
               <sscc>101</sscc>
               <parent>
                  <sscc>205</sscc>
               </parent>               
            </logistic>
            <logistic>
               <sscc>102</sscc>
               <parent>
                  <sscc>206</sscc>
               </parent>               
            </logistic>
         </warehousingOperationsLocation>
      </warehousingOperationsTransaction>   

   </warehousingNotification>
</wONM>

xslt xslt-1.0
1个回答
-1
投票

这可以使用XSLT 2.0分组来实现,下面是完整的XSLT代码来实现所需的输出。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:output indent="yes"></xsl:output>

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

    <xsl:template match="*:wONM">
        <wONM>
            <xsl:apply-templates select="*:Standard"></xsl:apply-templates>
            <warehousingNotification>
                <xsl:apply-templates select="*:warehousingNotification/*:warehousingIdentification"/>
                <warehousingOperationsTransaction>
                    <xsl:apply-templates select="*:warehousingNotification/*:warehousingOperationsTransaction/*:SNumber"/>
                    <warehousingOperationsLocation>
                        <xsl:apply-templates select="*:warehousingNotification/*:warehousingOperationsTransaction/*:warehousingOperationsLocation/*:inventoryLocation"></xsl:apply-templates>
                        <xsl:for-each-group select="*:warehousingNotification//*:logistic" group-by="*:parent/*:sscc">
                            <logisticaaa>
                                <xsl:for-each select="current-group()">
                                    <sscc>
                                        <xsl:value-of select="./*:sscc"/>
                                    </sscc>
                                </xsl:for-each> 
                                <parent>
                                    <sscc><xsl:value-of select="current-grouping-key()"/></sscc>
                                </parent>
                            </logisticaaa>
                        </xsl:for-each-group>
                    </warehousingOperationsLocation>
                </warehousingOperationsTransaction>
            </warehousingNotification>            
        </wONM>
    </xsl:template>

</xsl:stylesheet>

1
投票

就像在评论中提到的,你没有表现出任何自己解决这个问题的尝试。

我不给你样式表(我已经写好了),而是把我按照的步骤分解出来,希望你能自己尝试。如果你在更新问题的时候表现出努力的尝试,我会把我的完整样式表加到我的答案中。

第1步

先进行身份转换。这样基本上输入什么就输出什么,不会有什么变化。

输入和输出之间可能有什么不同的细节我就不多说了。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

</xsl:stylesheet>

第二步

我在您的输出中看到的第一个变化(按文档顺序)是您将所有的 warehousingOperationsTransaction 元素合并成一个元素。

要做到这一点,我们可以添加一个与父元素匹配的模板(warehousingNotification).

同样,我从xsl:copyxsl:apply-templates开始,得到同样的输出不变;就像身份转换一样)。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

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

</xsl:stylesheet>

第3步:使用xsl:copyxsl:apply-templates,得到同样的输出,没有变化;就像身份转换一样。

现在我们可以改变 xsl:apply-templates 不处理现有的 warehousingOperationsTransaction 元素。

我们也可以创建新的 warehousingOperationsTransaction 以及其他静态元素(SNumber, warehousingOperationsLocationinventoryLocation).

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="parent" match="parent/sscc" use="."/>
  <xsl:key name="sscc_by_parent" match="sscc" use="../parent/sscc"/>

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


  <!--step 2-->
  <xsl:template match="warehousingNotification">
    <xsl:copy>
      <!--step 3 (exclude warehousingOperationsTransaction and add a new one)-->
      <xsl:apply-templates select="@*|node()[not(self::warehousingOperationsTransaction)]"/>
      <warehousingOperationsTransaction>
        <SNumber>1</SNumber>
        <warehousingOperationsLocation>
          <inventoryLocation/>          
        </warehousingOperationsLocation>
      </warehousingOperationsTransaction>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

- 计时 -

对于接下来的步骤,我只在XSLT中提供注释,在这里我将把每个步骤的代码放在这里。这是你接手的地方,如果你需要帮助,可以带着具体问题回来。(除了xsl:key's,我会给你这些。)

在接下来的步骤中,你需要学习Muenchian分组。一个很好的参考资料可以在这里找到。Jeni的XSLT页面。使用Muenchian方法进行分组

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!--step 4-->

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


  <!--step 2-->
  <xsl:template match="warehousingNotification">
    <xsl:copy>
      <!--step 3 (exclude warehousingOperationsTransaction and add a new one)-->
      <xsl:apply-templates select="@*|node()[not(self::warehousingOperationsTransaction)]"/>
      <warehousingOperationsTransaction>
        <SNumber>1</SNumber>
        <warehousingOperationsLocation>
          <inventoryLocation/>
          <!--step 5 (create logistic for each parent)-->
              <!--step 6 (output the sscc's based on parent (current context))-->
        </warehousingOperationsLocation>
      </warehousingOperationsTransaction>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

第四步

您需要创建 xsl:key 元素进行分组。

由于您正在创建一个新的 logic 元素的每一个独特的 parent/sscc,为父母创建一个密钥。

你还需要为所有的 logistic/sscc 基于同胞的元素 parent/sscc.

为了帮助你开始,这些是我使用的键。

<xsl:key name="parent" match="parent/sscc" use="."/>
<xsl:key name="sscc_by_parent" match="logistic/sscc" use="../parent/sscc"/>

第五步

创建一个 logistic/parent 元素,为每个(xsl:for-each)唯一的父元素。

这一点的关键(没有双关语的意思)是看Jenny的例子,其中提到"有几种通用的方法来测试两个节点是否相同。".

提示:你将使用 key() 作用于 谓词. 你要使用 "父 "键。

第六步

现在我们需要插入所有的 sscc 中的元素 logistic 元素。

要做到这一点,你可以使用 xsl:copy-of 前置 parent 元素。你将使用 key() 功能,再次访问 sscc_by_parent 键。

唯一棘手的是,第二个参数应该用什么来代替 key(). 由于你可能在第5步中使用了xsl:for-each来选择 .//parent/sscc,我们需要的值已经是 当前 语境。(链接是提示。)

祝你好运!

这至少应该足以让你入门。如果没有,请考虑接受正规培训或聘请顾问。

EDIT: 转到XSLT 2.0是个正确的决定。这里是1.0的样式表,也许将来会对别人有帮助。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!--step 4-->
  <xsl:key name="parent" match="parent/sscc" use="."/>
  <xsl:key name="sscc_by_parent" match="logistic/sscc" use="../parent/sscc"/>

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


  <!--step 2-->
  <xsl:template match="warehousingNotification">
    <xsl:copy>
      <!--step 3 (exclude warehousingOperationsTransaction and add a new one)-->
      <xsl:apply-templates select="@*|node()[not(self::warehousingOperationsTransaction)]"/>
      <warehousingOperationsTransaction>
        <SNumber>1</SNumber>
        <warehousingOperationsLocation>
          <inventoryLocation/>
          <!--step 5 (create logistic for each parent)-->
          <xsl:for-each select=".//parent/sscc[count(.|key('parent', .)[1]) = 1]">
            <logistic>
              <!--step 6 (output the sscc's based on parent (current context))-->
              <xsl:copy-of select="key('sscc_by_parent', current())"/>
              <parent>
                <xsl:copy-of select="."/>
              </parent>
            </logistic>
          </xsl:for-each>
        </warehousingOperationsLocation>
      </warehousingOperationsTransaction>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

摆弄一下。http:/xsltfiddle.liberty-development.net3MvmXiZ


0
投票

这看起来像是一个标准的分组问题。在XSLT 2.0以上的版本中,它是指 <xsl:for-each-group select=".//logistic" group-by="parent/sscc">. XSLT 1.0中的分组是比较困难的,但如果你实在无法向XSLT 2.0处理器迈进,那就好好读读Muenchian的分组技术吧,这些技术在每一本XSLT 1.0的教材和很多在线教程中都有涉及。

© www.soinside.com 2019 - 2024. All rights reserved.