使用XSLT平坦具有重复子节点的节点



我有一个以下结构的文档(这只是一个帮助我用语言表达问题的示例),我试图将其扁平化。扁平化是指用几个<Event>复制所有的<Report_Entry>节点,这样每个<Report_Entry>节点只包含一个<Event>

What I have:

<?xml version="1.0"?>
<Report_Data>
  <Report_Entry>
    <ID>1</ID>
    <Event>
      <Start_Date>2011-09-06</Start_Date>
      <End_Date>2011-09-10</End_Date>
    </Event>
    <Event>
      <Start_Date>2011-09-10</Start_Date>
      <End_Date>2011-09-15</End_Date>
    </Event>
    <Event>
      <Start_Date>2011-09-15</Start_Date>
      <End_Date>2011-09-20</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>2</ID>
    <Event>
      <Start_Date>2011-09-20</Start_Date>
      <End_Date>2011-09-25</End_Date>
    </Event>
    <Event>
      <Start_Date>2011-09-25</Start_Date>
      <End_Date>2011-09-30</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>3</ID>
    <Event>
      <Start_Date>2011-09-30</Start_Date>
      <End_Date>2011-10-05</End_Date>
    </Event>
  </Report_Entry>
</Report_Data>

我想要得到的:

<?xml version="1.0"?>
<Report_Data>
  <Report_Entry>
    <ID>1</ID>
    <Event>
      <Start_Date>2011-09-06</Start_Date>
      <End_Date>2011-09-10</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>1</ID>
    <Event>
      <Start_Date>2011-09-10</Start_Date>
      <End_Date>2011-09-15</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>1</ID>
    <Event>
      <Start_Date>2011-09-15</Start_Date>
      <End_Date>2011-09-20</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>2</ID>
    <Event>
      <Start_Date>2011-09-20</Start_Date>
      <End_Date>2011-09-25</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>2</ID>
    <Event>
      <Start_Date>2011-09-25</Start_Date>
      <End_Date>2011-09-30</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>3</ID>
    <Event>
      <Start_Date>2011-09-30</Start_Date>
      <End_Date>2011-10-05</End_Date>
    </Event>
  </Report_Entry>
</Report_Data>

下面是我使用的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="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="Report_Entry">
  <xsl:for-each select="Event">
    <Report_Entry>
      <xsl:copy-of select="../*[not(self::Event)]"/>
      <xsl:copy-of select="."/>
    </Report_Entry>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

它是有效的,尽管我觉得可能有一个更好、更快、更通用的解决方案。特别是,我不喜欢"硬编码"<Report_Entry>,因为这样我就无法复制它的属性(如果有的话)。是否有其他方法/模板来处理这个问题?

这么简单:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:template match="/*">
  <Report_Data>
    <xsl:apply-templates select="*/Event"/>
  </Report_Data>
 </xsl:template>
 <xsl:template match="Event">
  <Report_Entry>
   <xsl:copy-of select="../ID | ."/>
  </Report_Entry>
 </xsl:template>
</xsl:stylesheet>

当对提供的XML文档应用此转换时:

<Report_Data>
  <Report_Entry>
    <ID>1</ID>
    <Event>
      <Start_Date>2011-09-06</Start_Date>
      <End_Date>2011-09-10</End_Date>
    </Event>
    <Event>
      <Start_Date>2011-09-10</Start_Date>
      <End_Date>2011-09-15</End_Date>
    </Event>
    <Event>
      <Start_Date>2011-09-15</Start_Date>
      <End_Date>2011-09-20</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>2</ID>
    <Event>
      <Start_Date>2011-09-20</Start_Date>
      <End_Date>2011-09-25</End_Date>
    </Event>
    <Event>
      <Start_Date>2011-09-25</Start_Date>
      <End_Date>2011-09-30</End_Date>
    </Event>
  </Report_Entry>
  <Report_Entry>
    <ID>3</ID>
    <Event>
      <Start_Date>2011-09-30</Start_Date>
      <End_Date>2011-10-05</End_Date>
    </Event>
  </Report_Entry>
</Report_Data>

生成所需的正确结果:

<Report_Data>
   <Report_Entry>
      <ID>1</ID>
      <Event>
         <Start_Date>2011-09-06</Start_Date>
         <End_Date>2011-09-10</End_Date>
      </Event>
   </Report_Entry>
   <Report_Entry>
      <ID>1</ID>
      <Event>
         <Start_Date>2011-09-10</Start_Date>
         <End_Date>2011-09-15</End_Date>
      </Event>
   </Report_Entry>
   <Report_Entry>
      <ID>1</ID>
      <Event>
         <Start_Date>2011-09-15</Start_Date>
         <End_Date>2011-09-20</End_Date>
      </Event>
   </Report_Entry>
   <Report_Entry>
      <ID>2</ID>
      <Event>
         <Start_Date>2011-09-20</Start_Date>
         <End_Date>2011-09-25</End_Date>
      </Event>
   </Report_Entry>
   <Report_Entry>
      <ID>2</ID>
      <Event>
         <Start_Date>2011-09-25</Start_Date>
         <End_Date>2011-09-30</End_Date>
      </Event>
   </Report_Entry>
   <Report_Entry>
      <ID>3</ID>
      <Event>
         <Start_Date>2011-09-30</Start_Date>
         <End_Date>2011-10-05</End_Date>
      </Event>
   </Report_Entry>
</Report_Data>

你的答案再简单不过了,所以在这方面不必担心。在编写代码(尤其是XSLT)时,代码的清晰性往往比其最终的效率重要得多。

对于硬编码的元素名称和复制属性,下面是一个开始:

<xsl:template match="Report_Entry">
  <xsl:variable name="parent-name" select="name()"/>
  <xsl:variable name="parent-attributes" select="@*"/>
  <xsl:for-each select="Event">
    <xsl:element name="{$parent-name}">
      <xsl:copy-of select="$parent-attributes"/>
      <xsl:copy-of select="../*[not(self::Event)]"/>
      <xsl:copy-of select="."/>
    </xsl:element>
  </xsl:for-each>
</xsl:template>

variable s用于隐藏存在于for-each之外的一些上下文。element创建了一个与原始元素相似的元素,无论它叫什么,第一个copy-of也通过复制原始元素的属性使其更有说服力。现在,如果你的数据突然有了属性,你就准备好了。

名称的非硬编码性在这种情况下没有多大意义,但如果您要将该部分分解到一个单独的模板中并从多个地方调用它,则会有很大意义:

<xsl:template name="collapse-the-thing">
  <xsl:param name="context"/>
  <xsl:param name="sub-element-name" select="'Event'"/>
  <xsl:variable name="parent-name" select="name($context)"/>
  <xsl:variable name="parent-attributes" select="$context/@*"/>
  <xsl:for-each select="$context/*[name()=$sub-element-name]">
    <xsl:element name="{$parent-name}">
      <xsl:copy-of select="$parent-attributes"/>
      <xsl:copy-of select="../*[name()!=$sub-element-name]"/>
      <xsl:copy-of select="."/>
    </xsl:element>
  </xsl:for-each>
</xsl:template>
<xsl:template match="Report_Entry">
  <xsl:call-template name="collapse-the-thing">
    <xsl:with-param name="context" select="."/>
  </xsl:call-template>
</xsl:template>
<xsl:template match="Some_Other_Entry">
  <xsl:call-template name="collapse-the-thing">
    <xsl:with-param name="context" select="."/>
    <xsl:param name="sub-element-name" select="'Happening'"/>
  </xsl:call-template>
</xsl:template>

希望这是有启发的。享受吧!

相关内容

  • 没有找到相关文章

最新更新