0

I want to split an XmlDocument into an array of XmlDocuments, where each splitted XmlDocument contains records of a certain period (Year/Month combination). The complicating factor, imo, is that the grouping should occur on nested elements.

Example input:

<?xml version="1.0" encoding="utf-8"?>
<Example>
  <RecordA>
    <RecordA1>
      <RecordA11>
        <ElementA11></ElementA11>
      </RecordA11>
    </RecordA1>
    <RecordA2>
      <ElementA2></ElementA2>
    </RecordA2>
  </RecordA>
  <RecordB>
    <RecordB1>
      <ElementB1></ElementB1>
      <RecordB11>
        <ElementB11></ElementB11>
        <RecordB111>
          <RecordB1111>
            <RecordB11111>
              <ElementB11111></ElementB11111>
            </RecordB11111>
            <ElementB1111></ElementB1111>
            <RecordB11112>
              <Dates>
                <StartDate>2014-05-29</StartDate>
                <EndDate>2014-05-29</EndDate>
              </Dates>
            </RecordB11112>
            <RecordB11112>
              <Dates>
                <StartDate>2014-06-02</StartDate>
                <EndDate>2014-06-02</EndDate>
              </Dates>
            </RecordB11112>
            <RecordB11112>
              <Dates>
                <StartDate>2014-05-21</StartDate>
                <EndDate>2014-05-21</EndDate>
              </Dates>
            </RecordB11112>
            <RecordB11112>
              <Dates>
                <StartDate>2014-04-09</StartDate>
                <EndDate>2014-04-09</EndDate>
              </Dates>
            </RecordB11112>
            <RecordB11112>
              <Dates>
                <StartDate>2014-06-05</StartDate>
                <EndDate>2014-06-05</EndDate>
              </Dates>
            </RecordB11112>
          </RecordB1111>
        </RecordB111>
      </RecordB11>
    </RecordB1>
  </RecordB>
</Example>

Wanted output:

<?xml version="1.0" encoding="utf-8"?>
<Examples>
  <Example>
    <RecordA>
      <RecordA1>
        <RecordA11>
          <ElementA11></ElementA11>
        </RecordA11>
      </RecordA1>
      <RecordA2>
        <ElementA2></ElementA2>
      </RecordA2>
    </RecordA>
    <RecordB>
      <RecordB1>
        <ElementB1></ElementB1>
        <RecordB11>
          <ElementB11></ElementB11>
          <RecordB111>
            <RecordB1111>
              <RecordB11111>
                <ElementB11111></ElementB11111>
              </RecordB11111>
              <ElementB1111></ElementB1111>
              <RecordB11112>
                <Dates>
                  <StartDate>2014-05-29</StartDate>
                  <EndDate>2014-05-29</EndDate>
                </Dates>
              </RecordB11112>
              <RecordB11112>
                <Dates>
                  <StartDate>2014-05-21</StartDate>
                  <EndDate>2014-05-21</EndDate>
                </Dates>
              </RecordB11112>
            </RecordB1111>
          </RecordB111>
        </RecordB11>
      </RecordB1>
    </RecordB>
  </Example>
  <Example>
    <RecordA>
      <RecordA1>
        <RecordA11>
          <ElementA11></ElementA11>
        </RecordA11>
      </RecordA1>
      <RecordA2>
        <ElementA2></ElementA2>
      </RecordA2>
    </RecordA>
    <RecordB>
      <RecordB1>
        <ElementB1></ElementB1>
        <RecordB11>
          <ElementB11></ElementB11>
          <RecordB111>
            <RecordB1111>
              <RecordB11111>
                <ElementB11111></ElementB11111>
              </RecordB11111>
              <ElementB1111></ElementB1111>
              <RecordB11112>
                <Dates>
                  <StartDate>2014-04-09</StartDate>
                  <EndDate>2014-04-09</EndDate>
                </Dates>
              </RecordB11112>
            </RecordB1111>
          </RecordB111>
        </RecordB11>
      </RecordB1>
    </RecordB>
  </Example>
  <Example>
    <RecordA>
      <RecordA1>
        <RecordA11>
          <ElementA11></ElementA11>
        </RecordA11>
      </RecordA1>
      <RecordA2>
        <ElementA2></ElementA2>
      </RecordA2>
    </RecordA>
    <RecordB>
      <RecordB1>
        <ElementB1></ElementB1>
        <RecordB11>
          <ElementB11></ElementB11>
          <RecordB111>
            <RecordB1111>
              <RecordB11111>
                <ElementB11111></ElementB11111>
              </RecordB11111>
              <ElementB1111></ElementB1111>
              <RecordB11112>
                <Dates>
                  <StartDate>2014-06-02</StartDate>
                  <EndDate>2014-06-02</EndDate>
                </Dates>
              </RecordB11112>
              <RecordB11112>
                <Dates>
                  <StartDate>2014-06-05</StartDate>
                  <EndDate>2014-06-05</EndDate>
                </Dates>
              </RecordB11112>
            </RecordB1111>
          </RecordB111>
        </RecordB11>
      </RecordB1>
    </RecordB>
  </Example>
</Examples>
René Bik
  • 5
  • 3
  • Do you want to create several result documents with XSLT 1.0? Or why do you say "I want to split an XmlDocument into an array of XmlDocuments"? Most XSLT 1.0 processors don't have support for an extension to create several result elements, and `xsl:result-document` is an XSLT 2.0 or later feature. – Martin Honnen Jun 11 '15 at 10:45
  • Also I don't see a difference between posted input and wanted output. – Martin Honnen Jun 11 '15 at 10:58
  • Sorry, my fault, I've updated the wanted result. – René Bik Jun 11 '15 at 11:08

1 Answers1

0

I think you can use Muenchian grouping to identify the first item in each group, then you need to recreate the tree for each group:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="group" match="RecordB11112" use="substring(Dates/StartDate, 1, 7)"/>

<xsl:template match="/">
  <Examples>
    <xsl:apply-templates select="//RecordB11112[generate-id() = generate-id(key('group', substring(Dates/StartDate, 1, 7))[1])]"/>
  </Examples>
</xsl:template>

<xsl:template match="RecordB11112">
  <xsl:variable name="to-be-copied" select="key('group', substring(Dates/StartDate, 1, 7))"/>
  <xsl:apply-templates select="/*" mode="recreate">
    <xsl:with-param name="to-be-copied" select="$to-be-copied"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="@* | node()" mode="recreate">
  <xsl:param name="to-be-copied"/>
  <xsl:copy>
    <xsl:apply-templates select="@*" mode="recreate"/>
    <xsl:apply-templates mode="recreate">
      <xsl:with-param name="to-be-copied" select="$to-be-copied"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

<xsl:template match="RecordB11112" mode="recreate">
  <xsl:param name="to-be-copied"/>
  <xsl:if test="$to-be-copied[generate-id() = generate-id(current())]">
    <xsl:copy-of select="."/>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thxs, that's what I was looking for, I was already trying with Muenchian grouping, but did not manage to copy the original parent structure. – René Bik Jun 11 '15 at 12:43