Combining XML using XSLT 1.0 [duplicate]

2019-09-20 10:44发布

This question already has an answer here:

I need to map the following but its difficult because it has different names:

<main>
    <order>
        <ID>123</ID>
        <Name>ABC</Name>
    </order>
    <order>
        <ID>4556</ID>
        <Name>AAA</Name>
        <ParentID>123</ParentID>
    </order>
</main>

The result should be:

<main>
    <order>
        <ID>123</ID>
        <Name>ABC</Name>
        <order>
            <ID>4556</ID>
            <Name>AAA</Name>
            <ParentID>123</ParentID>
        </order>
    </order>
</main>

2条回答
Luminary・发光体
2楼-- · 2019-09-20 10:58

One approach to copy all order nodes with index n>1 into the first one is the following XSLT:

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

    <xsl:template match="text()" />    <!-- suppresses copying of text() nodes -->

    <xsl:template match="main">        <!-- replicates the "main" node -->
      <main>
        <xsl:apply-templates />
      </main>
    </xsl:template>

    <xsl:template match="order[1]">    <!-- matches the first "order" node and copies all following ones -->
      <order>
        <xsl:copy-of select="*" />
        <xsl:copy-of select="following-sibling::order" />
      </order>   
    </xsl:template>    
</xsl:stylesheet>

The output looks like this:

<?xml version="1.0"?>
<main>
    <order>
        <ID>123</ID>
        <Name>ABC</Name>
        <order>
            <ID>4556</ID>
            <Name>AAA</Name>
            <ParentID>123</ParentID>
        </order>
    </order>
</main>
查看更多
来,给爷笑一个
3楼-- · 2019-09-20 11:13

Like @michael.hor257k said, conceptually this question is the same as your previous question. I think you're just not understanding the concept. Hopefully the comments in my example will help.

If I understand the question correctly, you want to nest order elements inside of their "parent" order element based on ParentID. Since we're basing it on the ParentID, that's what we'll use for our key...

XML Input

<main>
    <order>
        <ID>123</ID>
        <Name>ABC</Name>
    </order>

    <order>
        <ID>4556</ID>
        <Name>AAA</Name>
        <ParentID>123</ParentID>
    </order>
</main>

XSLT 1.0

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

  <!--Create a key containing order elements that contain a non-empty ParentID.-->
  <xsl:key name="orderByParentId" match="order[string(ParentID)]" use="ParentID"/>

  <!--Identity transform (https://www.w3.org/TR/xslt#copying)-->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/main">
    <xsl:copy>
      <!--To get the high level order elements, only apply-templates when order
      does not contain a non-empty ParentID child.-->
      <xsl:apply-templates 
        select="@*|order[not(string(ParentID))]"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="order">
    <xsl:copy>
      <!--Don't apply-templates to ParentID; we don't want to keep those.
      Do apply-templates to the key 'orderByParentId' when the key matches
      the current order's ID child.-->
      <xsl:apply-templates 
        select="@*|*[not(self::ParentID)]|key('orderByParentId',ID)"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Output

<main>
   <order>
      <ID>123</ID>
      <Name>ABC</Name>
      <order>
         <ID>4556</ID>
         <Name>AAA</Name>
      </order>
   </order>
</main>
查看更多
登录 后发表回答