我有一份关于以下结构的文件(这只是一个帮助我用语言表达问题的例子),我正试图压扁。扁平化我的意思是复制所有<Report_Entry>
个节点,其中包含多个<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>
,因为这样我就无法复制其属性(如果有的话)。还有其他方法/模板来处理这个问题吗?
答案 0 :(得分: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>
答案 1 :(得分: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>
variable
用于存储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>
希望这很有启发性。享受!