0

为了结合每道菜的所有条件和测量值,我将如何转换以下内容?我正在努力组合重复的子元素。

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

1 回答 1

2

为了完全灵活,您可能希望避免硬编码Dish1Dish2并允许任意数量的菜肴。实际上,您希望通过实验 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 包含两个与Experiment的子元素匹配的模板,因此 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 2.0 的 XSLT

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

请注意,在这两种情况下,任何地方都没有提到Dish1Dish,因此您可以轻松拥有Dish3或更多,而无需更改 XSLT。

于 2013-04-08T22:37:03.747 回答