0

我有一个以下结构的文档(这只是一个帮助我表达问题的示例),我正在尝试将其展平。<Report_Entry>通过展平,我的意思是用几个s复制所有节点,<Event>以便每个<Report_Entry>节点只包含一个<Event>

我有的:

<?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>,因为这样我就无法复制它的属性(如果有的话)。有没有其他方法/模板来处理这个问题?

4

2 回答 2

1

就这么简单

<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>
于 2013-05-14T03:38:35.180 回答
0

您的答案再简单不过了,因此无需为此担心。在编写代码时,尤其是 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>

variables 用于存储一些上下文,因为它存在于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>

希望那是有启发性的。享受!

于 2013-05-13T20:57:29.220 回答