如何使用XSLT只获取某些行和某些列?

时间:2011-03-11 08:25:53

标签: xml xslt

如何使用XSLT转换此XML文件:

<file>
    <row>
        <cell></cell>
        <cell>(info...)</cell>
        <cell></cell>
    </row>
    <row>
        <cell>first name</cell>
        <cell>last name</cell>
        <cell>age</cell>
    </row>
    <row>
        <cell>Jim</cell>
        <cell>Smith</cell>
        <cell>34</cell>
    </row>
    <row>
        <cell>Roy</cell>
        <cell>Rogers</cell>
        <cell>22</cell>
    </row>
    <row>
        <cell>Hank</cell>
        <cell>Grandier</cell>
        <cell>23</cell>
    </row>
    <row>
        <cell>(info...)</cell>
        <cell></cell>
        <cell>(info...)</cell>
    </row>

    <row>
        <cell>Sally</cell>
        <cell>Cloud</cell>
        <cell>26</cell>
    </row>

    <row>
        <cell>John</cell>
        <cell>Randall</cell>
        <cell>44</cell>
    </row>  

</file>

到这个XML文件:

<file>
    <row>
        <cell>Jim</cell>
        <cell>34</cell>
    </row>
    <row>
        <cell>Roy</cell>
        <cell>22</cell>
    </row>
    <row>
        <cell>Sally</cell>
        <cell>26</cell>
    </row>
    <row>
        <cell>John</cell>
        <cell>44</cell>
    </row>  
</file>

基本上规则是:

  • 第一和第三列(名字和年龄)
  • 仅限某些范围内的行,例如在上面的简单示例中,它将是行3-5 行7-8 ,所以我假设我需要某种带有此信息的映射表

附录

以下是我使用MarcoS关于params的提示的解决方案:

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

    <xsl:output method="xml" indent="yes" omit-xml-declaration="no" />

    <xsl:param name="range-1-begin"  select="3"/>
    <xsl:param name="range-1-end"  select="4"/>

    <xsl:param name="range-2-begin"  select="6"/>
    <xsl:param name="range-2-end"  select="7"/>

    <xsl:template match="file">
        <marco>
            <xsl:for-each select="row">
                <xsl:if test="(position() &gt;= $range-1-begin and position() &lt;= $range-1-end)
                    or (position() &gt;= $range-2-begin and position() &lt;= $range-2-end)">
                    <row>
                        <xsl:for-each select="cell">
                            <xsl:if test="position() = 1 or 
                                position() = 3">
                                <cell>
                                    <xsl:value-of select="."/>
                                </cell>
                            </xsl:if>
                        </xsl:for-each>
                    </row>
                </xsl:if>
            </xsl:for-each>
        </marco>
    </xsl:template>

</xsl:stylesheet>

3 个答案:

答案 0 :(得分:5)

这是一种可能的解决方案(可能不是很优雅):

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

    <xsl:output method="xml" indent="yes" omit-xml-declaration="no" />

    <xsl:template match="file">
        <file>
            <xsl:for-each select="row">
                <xsl:if test="(position() >= 3 and position() &lt; 5)
                    or (position() >= 7 and position() &lt;= 8)">
                    <row>
                        <xsl:for-each select="cell">
                            <xsl:if test="position() = 1 or 
                                position() = 3">
                                <cell>
                                    <xsl:value-of select="."/>
                                </cell>
                            </xsl:if>
                        </xsl:for-each>
                    </row>
                </xsl:if>
            </xsl:for-each>
        </file>
    </xsl:template>

</xsl:stylesheet>

基本上,您可以使用XPath position()函数来选择所需的rowcell元素的范围。

答案 1 :(得分:2)

这是一个XSLT,可以完成你描述的内容。

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="iso-8859-1" indent="yes" omit-xml-declaration="no"/>
  <xsl:template match="file">
    <xsl:copy>
      <xsl:apply-templates select="row[(position()&gt;=3 and position()&lt;=5) or (position()&gt;=7 and position()&lt;=8)]" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="row">
    <xsl:copy>
      <xsl:apply-templates select="cell[position()=1 or position()=3]" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="cell">
    <xsl:copy-of select="." />
  </xsl:template>
</xsl:stylesheet>

要在输出中选择所需的行,我想我首先要用一个可用作过滤器的属性来标记它们。 在调用XSLT的代码中,您可以在加载XML文档之后和应用转换之前使用DOM方法来完成。例如,保留吉姆史密斯但丢弃罗伊罗杰斯:

<row keep="-1">
    <cell>Jim</cell>
    <cell>Smith</cell>
    <cell>34</cell>
</row>
<row>
    <cell>Roy</cell>
    <cell>Rogers</cell>
    <cell>22</cell>
</row>

并将XSLT中的行更改为:

<xsl:apply-templates select="row[@keep=-1]" />

答案 2 :(得分:2)

这可能是最简单,最简短的解决方案,也基于使用和覆盖身份规则:

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

 <my:params>
  <row-range start="3" end="5"/>
  <row-range start="7" end="8"/>
  <cell-positions>
   <pos>1</pos>
   <pos>3</pos>
  </cell-positions>
 </my:params>

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

 <xsl:template match=
  "row[(not(position() >= document('')/*/my:params/row-range[1]/@start)
     or
       position() > document('')/*/my:params/row-range[1]/@end
       )
     and
      (not(position() >= document('')/*/my:params/row-range[2]/@start)
     or
       position() > document('')/*/my:params/row-range[2]/@end
       )
      ]
  "/>

 <xsl:template match=
  "cell[not(position()=document('')/*/my:params/cell-positions/*)]"/>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<file>
    <row>
        <cell></cell>
        <cell>(info...)</cell>
        <cell></cell>
    </row>
    <row>
        <cell>first name</cell>
        <cell>last name</cell>
        <cell>age</cell>
    </row>
    <row>
        <cell>Jim</cell>
        <cell>Smith</cell>
        <cell>34</cell>
    </row>
    <row>
        <cell>Roy</cell>
        <cell>Rogers</cell>
        <cell>22</cell>
    </row>
    <row>
        <cell>Hank</cell>
        <cell>Grandier</cell>
        <cell>23</cell>
    </row>
    <row>
        <cell>(info...)</cell>
        <cell></cell>
        <cell>(info...)</cell>
    </row>
    <row>
        <cell>Sally</cell>
        <cell>Cloud</cell>
        <cell>26</cell>
    </row>
    <row>
        <cell>John</cell>
        <cell>Randall</cell>
        <cell>44</cell>
    </row>
</file>

产生了想要的正确结果:

<file>
   <row>
      <cell>Jim</cell>
      <cell>34</cell>
   </row>
   <row>
      <cell>Roy</cell>
      <cell>22</cell>
   </row>
   <row>
      <cell>Hank</cell>
      <cell>23</cell>
   </row>
   <row>
      <cell>Sally</cell>
      <cell>26</cell>
   </row>
   <row>
      <cell>John</cell>
      <cell>44</cell>
   </row>
</file>