XLST将后代元素移动到最高级别

时间:2015-12-22 14:26:39

标签: .net xml xslt flatten

给定具有以下结构的XML:

<Sample>
  <Version>6</Version>
  <Date>2012-05-11</Date>
  <Header>
    <CreatedDate>2015-12-02</CreatedDate>
    <CreatedTime>10:31:42</CreatedTime>
  </Header>
  <Message>
    <Group>1</Group> 
    <Type>1</Type>
    <Protocol>1</Protocol>
    <MessageHeader>
      <MessageReferenceNumber>1</MessageReferenceNumber>
    </MessageHeader>
    <TransactionHeader>
      <ReportPeriodStartDate>2002-04-01</ReportPeriodStartDate>
      <ReportPeriodEndDate>2015-11-30</ReportPeriodEndDate>
    </TransactionHeader>
    <Episode>
      <Person>
        <General>
          <Verified>
            <Status>02</Status>
            <Identifier>001</Identifier>
            <PersonName>
              <Name>
                <FirstName>Foo</FirstName>
                <Surname>Bar</Surname>
              </Name>
            </PersonName>
            <Address>
              <AddressLine></AddressLine>
              <AddressLine>Street</AddressLine>
              <AddressLine>Town</AddressLine>
              <AddressLine>City</AddressLine>
            </Address>
          </Verified>
        </General>
      </Person>
      <Session>
        <Input>
          <StartDate>2015-10-31</StartDate>
          <StartTime>17:15:00</StartTime>
        </Input>
        <Output>
          <StatusCode>8</StatusCode>
          <LocationCode>9</LocationCode>
        </Output>
      </Session>
    </Episode>
    <MessageTrailer>
      <MessageReferenceNumber>1</MessageReferenceNumber>
    </MessageTrailer>
  </Message>
  <Trailer>
    <RecordCount>1</RecordCount>
  </Trailer>
</Sample>

是否可以展平XML结构,以便Message元素中的所有元素都处于同一级别,如下所示。

<Sample>
  <Version>6</Version>
  <Date>2012-05-11</Date>
  <Header>
    <CreatedDate>2015-12-02</CreatedDate>
    <CreatedTime>10:31:42</CreatedTime>
  </Header>
  <Message>
    <Group>1</Group> 
    <Type>1</Type>
    <Protocol>1</Protocol>
    <!-- <MessageHeader></MessageHeader> -->
    <MessageReferenceNumber>1</MessageReferenceNumber>
    <!-- <TransactionHeader></TransactionHeader> -->
    <ReportPeriodStartDate>2002-04-01</ReportPeriodStartDate>
    <ReportPeriodEndDate>2015-11-30</ReportPeriodEndDate>
    <Episode></Episode>
    <!-- <Person></Person> -->
    <!-- <General></General> -->
    <!-- <Verified></Verified> -->
    <Status>02</Status>
    <Identifier>001</Identifier>
    <!-- <PersonName></PersonName> -->
    <!-- <Name></Name> -->
    <FirstName>Foo</FirstName>
    <Surname>Bar</Surname>
    <!-- <Address></Address> -->
    <AddressLine></AddressLine>
    <AddressLine>Street</AddressLine>
    <AddressLine>Town</AddressLine>
    <AddressLine>City</AddressLine>
    <!-- <Session></Session> -->
    <!-- <Input></Input> -->
    <StartDate>2015-10-31</StartDate>
    <StartTime>17:15:00</StartTime>
    <!-- <Output></Output> -->
    <StatusCode>8</StatusCode>
    <LocationCode>9</LocationCode>
    <!-- <MessageTrailer></MessageTrailer> -->
    <MessageReferenceNumber>1</MessageReferenceNumber>
  </Message>
  <Trailer>
    <RecordCount>1</RecordCount>
  </Trailer>
</Sample>

注释掉的元素不一定是必需的,但如果它更简单就可以保留。

我正在寻找一些通用的东西,无论XML结构如何都可以重用。我的想法是样式表将基于身份模板,并将检查是否有元素的后代,其中将输出那些没有后代的元素。

2 个答案:

答案 0 :(得分:0)

XSLT

以下XSLT展平了在每个<Message>元素下找到的所有“叶子”节点:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />

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

    <!-- match child elements of <Message> -->
    <xsl:template match="Message/*">
        <!-- select "leaf" elements (elements without child elements) -->
        <xsl:for-each select="descendant-or-self::*[not(*)]">
            <xsl:copy>
                <xsl:value-of select="text()"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

输出

<Sample>
    <Version>6</Version>
    <Date>2012-05-11</Date>
    <Header>
        <CreatedDate>2015-12-02</CreatedDate>
        <CreatedTime>10:31:42</CreatedTime>
    </Header>
    <Message>
        <Group>1</Group>
        <Type>1</Type>
        <Protocol>1</Protocol>
        <MessageReferenceNumber>1</MessageReferenceNumber>
        <ReportPeriodStartDate>2002-04-01</ReportPeriodStartDate>
        <ReportPeriodEndDate>2015-11-30</ReportPeriodEndDate>
        <Status>02</Status>
        <Identifier>001</Identifier>
        <FirstName>Foo</FirstName>
        <Surname>Bar</Surname>
        <AddressLine/>
        <AddressLine>Street</AddressLine>
        <AddressLine>Town</AddressLine>
        <AddressLine>City</AddressLine>
        <StartDate>2015-10-31</StartDate>
        <StartTime>17:15:00</StartTime>
        <StatusCode>8</StatusCode>
        <LocationCode>9</LocationCode>
        <MessageReferenceNumber>1</MessageReferenceNumber>
    </Message>
    <Trailer>
        <RecordCount>1</RecordCount>
    </Trailer>
</Sample>

答案 1 :(得分:0)

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

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

    <!--For any element that is a descendant of Message and has a child element, 
        generate a comment and then process it's children-->
    <xsl:template match="Message//*[*]">
        <xsl:comment>&lt;<xsl:value-of select="name()"/>>&lt;/<xsl:value-of select="name()"/>></xsl:comment>
      <xsl:apply-templates select="node()"/>
    </xsl:template>

</xsl:stylesheet>