【问题标题】:XSLT duplicate parent element for each occurrence of a child node, but with only its following siblingsXSLT 为每个子节点的出现重复父元素,但只有其以下兄弟节点
【发布时间】:2018-10-24 11:55:33
【问题描述】:

我的输入 XML 是

<DataArea>
  <ReceiveDelivery>
      <ReceiveDeliveryHeader>
          .....
      </ReceiveDeliveryHeader>
      <ReceiveDeliveryItem>
            ....
      </ReceiveDeliveryItem>
      <ReceiveDeliveryItem>
            ....
      </ReceiveDeliveryItem>
      <ReceiveDeliveryHeader>
          .....
      </ReceiveDeliveryHeader>
      <ReceiveDeliveryItem>
            ....
      </ReceiveDeliveryItem>
 </ReceiveDelivery>
</DataArea>

而想要的输出是

<DataArea>
      <ReceiveDelivery>
          <ReceiveDeliveryHeader>
              .....
          </ReceiveDeliveryHeader>
          <ReceiveDeliveryItem>
                ....
          </ReceiveDeliveryItem>
          <ReceiveDeliveryItem>
                ....
          </ReceiveDeliveryItem>
       </ReceiveDelivery>
       <ReceiveDelivery>
          <ReceiveDeliveryHeader>
              .....
          </ReceiveDeliveryHeader>
          <ReceiveDeliveryItem>
                ....
          </ReceiveDeliveryItem>
       </ReceiveDelivery>
     </DataArea>

标题后面可以有 1 个或多个项目。我希望为每个标题和仅跟随该标题的项目复制 ReceiveDelivery 父节点。请帮忙。

感谢 Martin 提供的意见。
我正在使用 XSLT 2.0。这是我的代码

<xsl:stylesheet version="2.0" xmlns="http://schema.infor.com/InforOAGIS/2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema" >

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

    <xsl:template match="ReceiveDelivery">
    <xsl:for-each-group select="*" group-starting-with="ReceiveDeliveryHeader">
      <ReceiveDelivery>         
              <xsl:copy-of select="current-group()"/>           
         </ReceiveDelivery>    
      </xsl:for-each-group> 
    </xsl:template> 
</xsl:stylesheet>   

这是应该的吗?但输出与输入相同。你能帮忙吗?

【问题讨论】:

  • 你能说你是否可以使用 XSLT 2.0 或更高版本?谢谢!

标签: xslt


【解决方案1】:

在 XSLT 2 或 3 中,使用for-each-group group-starting-with 是一个简单的分组问题:

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

  <xsl:mode on-no-match="shallow-copy"/>

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

  <xsl:template match="ReceiveDelivery">
      <xsl:for-each-group select="*" group-starting-with="ReceiveDeliveryHeader">
          <xsl:copy select="..">
              <xsl:copy-of select="current-group()"/>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94hvTA2

示例是 XSLT 3,但分组对 XSLT 2 的工作方式相同,只是您需要拼出 xsl:mode 作为身份转换模板并使用显式文字结果元素 &lt;ReceiveDelivery&gt;&lt;xsl:element name="{name(..)}"&gt; 而不是&lt;xsl:copy select=".."&gt;

【讨论】:

  • 感谢您的回答。我正在使用 XSLT 2.0。我已经用我写的 xslt 编辑了这个问题。但输出与输入相同。你能查一下吗?
  • 我怀疑您的“真实”XML 输入示例与您目前显示的不同,并且使用一个或多个命名空间,请编辑您的问题并显示最少但完整且格式良好的示例您拥有的 XML、您使用的 XSLT、您获得的结果和您想要的结果,以及有关使用的 XSLT 处理器的信息。
  • 请参阅xsltransform.hikmatu.com/94hvTyH 以获取 XSLT 2 示例,该示例使用您的问题中的输入以及我建议的分组加上身份转换模板,它肯定会根据要求对元素进行分组和包装。
  • 如果您的 XML 输入在命名空间中有元素,请参阅 xsltransform.hikmatu.com/94hvTyH/1xpath-default-namespace="http://example.com/foo" 的适配。
  • 非常感谢。您的改编 xsltransform.hikmatu.com/94hvTyH/1 非常有用。我的输入 XML 在命名空间中有元素。当我修改我的 XSLT 时,我得到了想要的输出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
相关资源
最近更新 更多