XSLT For-Each循环从枚举标签中获取数据?

时间:2013-04-19 16:28:49

标签: xml xslt foreach

我已经提供了一个SML文件,其中设计者(不在我公司,所以我无法控制)创建了一些我需要消耗的数据;但是他们设置了枚举标签,所以我很难创建一个循环来读取数据。

他们的代码看起来像

   <Root>
    <Subjects>
    <...more XML Data>
    <Data>
      <...other XML Data>
      <Demographic_Information>
            <Age1>33</Age1>
            <Age2>66</Age2>
            <Age3 />
            <Age4 />
            <Age5 />
            <Age6 />
            <Age7 />
            <Age8 />
            <Age9 />
            <Age10 />
            <Gender1>M</Gender1>
            <Gender2>F</Gender2>
            <Gender3 />
            <Gender4 />
            <Gender5 />
            <Gender6 />
            <Gender7 />
            <Gender8 />
            <Gender9 />
            <Gender10 />
            <Race1>W</Race1>
            <Race2>H</Race2>
            <Race3 />
            <Race4 />
            <Race5 />
            <Race6 />
            <Race7 />
            <Race8 />
            <Race9 />
            <Race10 />
        </Demographic_Information>
        </...other XML Data>
    </Data>
    </...more XML Data>
   </Subjects>
  </Root>

我只需要遍历这一点,并确保Age1,Gender1和Race1进入我的数据,如

<Person subject="1">
    <Age>33</Age>
    <Gender>M</Gender>
    <Race>W</Race>
</Person>
<Person subject="2">
    <Age>66</Age>
    <Gender>F</Gender>
    <Race>A</Race>
</Person>

这是较大集合中的数据子集,但如果可能,我需要将其转换为此格式。我确信它可以做到,我只是不知道如何去做。

我的XSLT是Microsoft Visual Studio 2008中的1.0版本。我从

开始
<xsl:template match="/Root/Subjects">

***修改后可以提供更好的问题样本。

3 个答案:

答案 0 :(得分:4)

这是一个有效的快速刺 - 我将继续看这个以找到效率,但我想给你一个答案。

编辑:感谢@MartinHonnen的简化。

当这个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable
     name="vNums"
     select="'0123456789'"/>

  <xsl:key
     name="kElemByNumber"
     match="Demographic_Information/*"
     use="translate(name(), translate(name(), $vNums, ''), '')"/>

  <xsl:template match="/*">
    <Demographic_Information>
      <xsl:apply-templates 
        select="*[generate-id() = 
                  generate-id(key(
                    'kElemByNumber',
                    translate(name(), translate(name(), $vNums, ''),
                    ''
                  ))[1])][normalize-space()]">
        <xsl:sort
          select="translate(name(), translate(name(), $vNums, ''), '')"
          data-type="number"/>
      </xsl:apply-templates>
    </Demographic_Information>
  </xsl:template>

  <xsl:template match="*">
    <Person subject="{position()}">
      <xsl:apply-templates
        select="key('kElemByNumber', position())"
        mode="children">
        <xsl:sort select="name()"/>
      </xsl:apply-templates>
    </Person>
  </xsl:template>

  <xsl:template match="*" mode="children">
    <xsl:element name="{translate(name(), $vNums, '')}">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

...适用于提供的源XML:

<Demographic_Information>
  <Age1>33</Age1>
  <Age2>66</Age2>
  <Age3/>
  <Age4/>
  <Age5/>
  <Age6/>
  <Age7/>
  <Age8/>
  <Age9/>
  <Age10/>
  <Gender1>M</Gender1>
  <Gender2>F</Gender2>
  <Gender3/>
  <Gender4/>
  <Gender5/>
  <Gender6/>
  <Gender7/>
  <Gender8/>
  <Gender9/>
  <Gender10/>
  <Race1>W</Race1>
  <Race2>H</Race2>
  <Race3/>
  <Race4/>
  <Race5/>
  <Race6/>
  <Race7/>
  <Race8/>
  <Race9/>
  <Race10/>
</Demographic_Information>

...生成了想要的结果:

<Demographic_Information>
  <Person subject="1">
    <Age>33</Age>
    <Gender>M</Gender>
    <Race>W</Race>
  </Person>
  <Person subject="2">
    <Age>66</Age>
    <Gender>F</Gender>
    <Race>A</Race>
  </Person>
</Demographic_Information>

答案 1 :(得分:0)

另一种选择:

<?xml version="1.0"?> 
<xsl:stylesheet
   version="1.0"     
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output encoding="utf-8" method="xml" indent="yes"/>

    <xsl:template match="/Demographic_Information">
        <Demographic_Information>
            <xsl:for-each select="./*[starts-with(name(), 'Age')][normalize-space()]">
                <xsl:variable name="i"><xsl:value-of select="string(position())"></xsl:value-of></xsl:variable>
                <Person>
                    <xsl:attribute name="subject"><xsl:value-of select="$i"/></xsl:attribute>
                    <Age>
                        <xsl:apply-templates select="node()" />
                    </Age>
                    <xsl:apply-templates select="../*[starts-with(name(), 'Gender')][position()=$i]"/>
                    <xsl:apply-templates select="../*[starts-with(name(), 'Race')][position()=$i]"/>
                </Person>
            </xsl:for-each>
        </Demographic_Information>
    </xsl:template>


    <xsl:template match="*[starts-with(name(), 'Age')]">
        <xsl:copy>
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[starts-with(name(), 'Gender')]">
        <Gender>
            <xsl:apply-templates select="node()" />
        </Gender>
    </xsl:template>
    <xsl:template match="*[starts-with(name(), 'Race')]">
        <Race>
            <xsl:apply-templates select="node()" />
        </Race>
    </xsl:template>


   <!-- defaults -->
    <xsl:template match="text()">
        <xsl:value-of select="."/>
    </xsl:template>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:-1)

以下将做。但也许不是最快的解决方案。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />

    <xsl:template match="@*|node()">
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="*[substring(name(),1,3) = 'Age']">
        <xsl:variable name="id" select="substring(name(),4)"/>
        <Person id="{$id}">
            <Age><xsl:value-of select="."/></Age>
            <Gender><xsl:value-of select="//*[name() =concat('Gender',$id)]"/></Gender>
            <Race><xsl:value-of select="//*[name() =concat('Race',$id)]"/></Race>
    </Person>
    </xsl:template>

    <xsl:template match="/" >
        <xsl:apply-templates />
    </xsl:template>
</xsl:stylesheet>