xslt
2013-04-08 45 views 0 likes 
0

我如何转换以下内容以合并每个Dish的所有条件和测量值?我正在努力结合重复的子元素。xslt-如何对重复元素进行分组并组合子元素和属性

<?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元素。

谢谢伊恩罗伯茨,让我写下我的失败尝试触发了一个想法,这导致了下面的工作解决方案。

<?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

您使用的是XSLT 1.0还是XSLT 2.0? – 2013-04-08 20:46:58

+0

我一直在使用1.0,但我不知道会阻止我使用2.0的任何原因。 – user2258779 2013-04-08 21:07:56

回答

2

要完全灵​​活的,你可能想避免硬编码Dish1Dish2,并允许任何数量的菜肴。实际上,你想通过他们的实验ID和盘子名称将'盘子'元素分组。

在XSLT 1.0中,您会使用称为Muenchian分组的技术。首先定义一个键,以便将菜元素

<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" /> 

而到了子元素结合“菜”的元素,你只需要一个唱乐模板

<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-各组是你最好的朋友。试试这个XSLT的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提到任何地方,这样你就可以轻松拥有Dish3以上,而无需改变XSLT。

+0

我应用了2.0解决方案,它工作,谢谢!我在我的应用程序中确实有3个“菜肴”,您的解决方案也获得了它们。 – user2258779 2013-04-08 22:59:34

相关问题