我如何改变以下内容以结合每个菜肴的所有条件和测量值?我正在努力结合重复的子元素。
<?xml version="1.0" encoding="UTF-8"?>
<Test>
<Experiment id='1'>
<Dish1>
<Conditions pressure='x' temp='y'/>
<Measurement timeStamp='8am' reading='y'/>
</Dish1>
<Dish2>
<Conditions pressure='x' temp='y'/>
<Measurement timeStamp='8am' reading='y'/>
</Dish2>
<Dish1>
<Conditions pressure='x' temp='y'/>
<Measurement timeStamp='2pm' reading='y'/>
</Dish1>
<Dish2>
<Conditions pressure='x' temp='y'/>
<Measurement timeStamp='2pm' reading='y'/>
</Dish2>
</Experiment>
<Experiment id='2'>
<Dish1>
<Conditions pressure='x' temp='y'/>
<Measurement timeStamp='9am' reading='y'/>
</Dish1>
</Experiment>
<Experiment id='2'>
<Dish1>
...
</Test>
期望的结果:
<?xml version="1.0" encoding="UTF-8"?>
<Test>
<Experiment id='1'>
<Dish1>
<Observation pressure='x' temp='y' timeStamp='8am' reading='y'/>
<Observation pressure='x' temp='y' timeStamp='2pm' reading='y'/>
</Dish1>
<Dish2>
<Observation pressure='x' temp='y' timeStamp='8am' reading='y'/>
<Observation pressure='x' temp='y' timeStamp='2pm' reading='y'/>
</Dish2>
</Experiment>
<Experiment id='2'>
<Dish1>
<Observation pressure='x' temp='y' timeStamp='9am' reading='y'/>
...
拜托,谢谢!
这是我到目前为止所尝试的内容:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="Experiment">
<xsl:copy>
<xsl:for-each select="Dish1">
<xsl:element name="Observation">
<xsl:attribute name="pressure"><xsl:value-of select="Conditions/@pressure"/></xsl:attribute>
<xsl:attribute name="temp"><xsl:value-of select="Conditions/@temp"/></xsl:attribute>
<xsl:attribute name="TimeStamp"><xsl:value-of select="Measurement/@TimeStamp"/></xsl:attribute>
<xsl:attribute name="reading"><xsl:value-of select="Measurement/@reading"/></xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- copy everthing not covered above-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在写下失败的尝试时,我提出了上述转变。它似乎工作,但我需要验证输出。任何建议/改进将不胜感激。谢谢。
...我的转换仅适用于第一个实验。当我添加:
<xsl:template match="Experiment">
<xsl:copy>
<xsl:for-each select="Dish2">
<xsl:element name="Observation">
<xsl:attribute name="pressure"><xsl:value-of select="Conditions/@pressure"/></xsl:attribute>
<xsl:attribute name="temp"><xsl:value-of select="Conditions/@temp"/></xsl:attribute>
<xsl:attribute name="TimeStamp"><xsl:value-of select="Measurement/@TimeStamp"/></xsl:attribute>
<xsl:attribute name="reading"><xsl:value-of select="Measurement/@reading"/></xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
...它找不到任何Dish2元素。
感谢Ian Roberts,让我写下我失败的尝试引发了一个想法,这导致了下面的工作解决方案。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="Experiment">
<xsl:copy>
<xsl:for-each select="Dish1">
<xsl:element name="Observation">
<xsl:attribute name="pressure"><xsl:value-of select="Conditions/@pressure"/></xsl:attribute>
<xsl:attribute name="temp"><xsl:value-of select="Conditions/@temp"/></xsl:attribute>
<xsl:attribute name="TimeStamp"><xsl:value-of select="Measurement/@TimeStamp"/></xsl:attribute>
<xsl:attribute name="reading"><xsl:value-of select="Measurement/@reading"/></xsl:attribute>
</xsl:element>
</xsl:for-each>
<xsl:for-each select="Dish2">
<xsl:element name="Observation">
<xsl:attribute name="pressure"><xsl:value-of select="Conditions/@pressure"/></xsl:attribute>
<xsl:attribute name="temp"><xsl:value-of select="Conditions/@temp"/></xsl:attribute>
<xsl:attribute name="TimeStamp"><xsl:value-of select="Measurement/@TimeStamp"/></xsl:attribute>
<xsl:attribute name="reading"><xsl:value-of select="Measurement/@reading"/></xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<!-- copy everthing not covered above-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:2)
为了完全灵活,您可能希望避免硬编码 Dish1 和 Dish2 并允许任意数量的菜肴。实际上,您希望根据实验ID和菜肴名称对“菜肴”元素进行分组。
在XSLT 1.0中,您将使用一种名为Muenchian Grouping的技术。首先定义一个键来分组您的菜肴元素
<xsl:key name="Dish" match="Experiment/*" use="concat(../@id, '-', local-name())" />
然后,为了获得实验中独特的“菜肴”元素,您必须选择组中首先出现的菜单元素为其名称
<xsl:apply-templates
select="*[generate-id() = generate-id(key('Dish', concat(../@id, '-', local-name()))[1])]" />
然后,要获得该组中的所有菜肴,您可以选择它们:
<xsl:apply-templates select="key('Dish', concat(../@id, '-', local-name()))" mode="group" />
要组合'Dish'元素的子元素,您只需要一个模板
<xsl:template match="Experiment/*" mode="group">
<Observation>
<xsl:apply-templates select="*/@*" />
</Observation>
</xsl:template>
这是完整的XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="Dish" match="Experiment/*" use="concat(../@id, '-', local-name())" />
<xsl:template match="Experiment">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="*[generate-id() = generate-id(key('Dish', concat(../@id, '-', local-name()))[1])]" />
</xsl:copy>
</xsl:template>
<xsl:template match="Experiment/*">
<xsl:copy>
<xsl:apply-templates select="key('Dish', concat(../@id, '-', local-name()))" mode="group" />
</xsl:copy>
</xsl:template>
<xsl:template match="Experiment/*" mode="group">
<Observation>
<xsl:apply-templates select="*/@*" />
</Observation>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意此处使用模式,因为XSLT包含两个与实验的子元素匹配的模板,因此XSLT需要区分它们。 (第一个是输出不同的'Dish'名称,第二个用于匹配和处理具有该名称的所有元素并组合子项。)
当应用于(截断的)XML示例时,输出以下内容
<Test>
<Experiment id="1">
<Dish1>
<Observation pressure="x" temp="y" timeStamp="8am" reading="y"/>
<Observation pressure="x" temp="y" timeStamp="2pm" reading="y"/>
</Dish1>
<Dish2>
<Observation pressure="x" temp="y" timeStamp="8am" reading="y"/>
<Observation pressure="x" temp="y" timeStamp="2pm" reading="y"/>
</Dish2>
</Experiment>
<Experiment id="2">
<Dish1>
<Observation pressure="x" temp="y" timeStamp="9am" reading="y"/>
</Dish1>
</Experiment>
</Test>
如果你可以使用XSLT 2.0,那么 xsl:for-each-group 是你最好的朋友。试试这个XSLT for XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Experiment">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:for-each-group select="*" group-by="local-name()">
<xsl:copy>
<xsl:apply-templates select="current-group()" />
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="Experiment/*">
<Observation>
<xsl:apply-templates select="*/@*" />
</Observation>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意,在这两种情况下都没有提及 Dish1 和 Dish ,因此您可以轻松地拥有 Dish3 或更多,而无需更改XSLT。