【问题标题】:XSLT 1.0 : Need to group the elements which is having the Parent IDXSLT 1.0:需要对具有父 ID 的元素进行分组
【发布时间】:2020-05-12 10:24:48
【问题描述】:

我需要将 Parent/sscc 与其 Logistic/sscc 相关联。我们需要在输入文件中检查相同的 Parent/sscc 并需要将其与其logistic/sscc 相关联。因此输出必须是logistic/sscc 与其父母/sscc。我提供了输入和输出的详细信息。 新代码不复制 Parent/sscc 及其逻辑 /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 代码。” 帮助你编写什么代码?你还没有开始。
  • 我来自 SAP 背景,因此检查通过 XSLT 代码实现此目的的可能性。我正在查看有关 XSLT 的博客。

标签: xml xslt xslt-1.0 xslt-grouping


【解决方案1】:

就像在 cmets 中提到的那样,您还没有尝试自己解决这个问题。

我将分解我遵循的步骤,而不是给你样式表(我已经写过),希望你可以自己尝试。如果您尝试更新问题,尝试显示努力,我会将完整的样式表添加到我的答案中。

第 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>

第 2 步

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

为此,我们可以添加一个与父级匹配的模板 (warehousingNotification)。

(同样,我从 xsl:copy/xsl: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:apply-templates 更改为不处理现有的warehousingOperationsTransaction 元素。

我们还可以创建新的 warehousingOperationsTransaction 以及其他静态元素(SNumberwarehousingOperationsLocationinventoryLocation)。

<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 中提供 cmets,我将在其中放置每个步骤的代码。如果您需要帮助,您可以在这里接手并提出具体问题。 (xsl:key 除外;我会给你那些。)

您需要了解 Muenchian Grouping 以进行后续步骤。可以在这里找到一个很好的参考:Jeni's XSLT Pages: Grouping Using the Muenchian Method

<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 元素进行分组。

由于您要为每个唯一的 parent/sscc 创建一个新的 logic 元素,因此请为父级创建一个键。

您还需要基于兄弟parent/sscc 的所有logistic/sscc 元素的键。

为了帮助您入门,以下是我使用的键:

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

第 5 步

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

这个问题的关键(不是双关语)是看 Jenny 的示例,其中提到“有几种通用方法可以测试两个节点是否相同”。

提示:您将在predicate 中使用key() 函数。您需要使用“父”键。

第 6 步

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

为此,您可以在新的parent 元素之前使用xsl:copy-of。您将再次使用key() 函数来访问sscc_by_parent 键。

其中唯一棘手的部分是 key() 的第二个参数使用什么。由于您可能在第 5 步中使用了 xsl:for-each 来选择 .//parent/sscc,因此我们需要的值已经是 current 上下文。 (链接是提示。)

祝你好运!

这至少足以让您入门。如果没有,请考虑进行正式培训或聘请顾问。

编辑:迁移到 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.net/3MvmXiZ

【讨论】:

  • 感谢您的指导。我迁移到 xslt 2.0 版本
  • @kjhughes - 哈哈,我知道,但当时我正处于教学状态。哦,好吧:-)
【解决方案2】:

这看起来像是一个标准的分组问题。在 XSLT 2.0+ 中,它是 &lt;xsl:for-each-group select=".//logistic" group-by="parent/sscc"&gt;。在 XSLT 1.0 中进行分组要困难得多,但如果您真的无法继续使用 XSLT 2.0 处理器,那么请阅读 Muenchian 分组技术,每本 XSLT 1.0 教科书和许多在线教程都介绍了这些技术。

【讨论】:

  • 很遗憾,我们的设置仅适用于 XSLT 1.0。
  • XSLT 1.0 已经过时了——现在是您考虑转向更新技术的时候了。找到愿意帮助解决 XSLT 1.0 问题的人将变得越来越困难,如果您升级,这些问题将很容易解决。
  • 是的,我查过了,但现在我只需要使用 1.0
  • @Sree - 请看我的回答。它包含一个指向 Muenchian 分组资源的有用链接。
【解决方案3】:

这可以使用 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>

【讨论】:

  • 感谢您的帮助,我需要 XSLT1.0 版本。我的系统不支持 XSLT2.0
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 2014-11-16
相关资源
最近更新 更多