Xml 如何使用XSLT仅获取特定行和特定列?

Xml 如何使用XSLT仅获取特定行和特定列?,xml,xslt,Xml,Xslt,如何使用XSLT转换此XML文件: <file> <row> <cell></cell> <cell>(info...)</cell> <cell></cell> </row> <row> <cell>first name</cell> <cel

如何使用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>
<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>

(信息…)
名字
姓
年龄
吉姆
史密斯
34
罗伊
罗杰斯
22
汉克
格朗迪耶
23
(信息…)
(信息…)
俏皮话
云彩
26
约翰
兰德尔
44
要创建此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>Sally</cell>
        <cell>26</cell>
    </row>
    <row>
        <cell>John</cell>
        <cell>44</cell>
    </row>  
</file>

吉姆
34
罗伊
22
俏皮话
26
约翰
44
基本上规则是:

  • 只有第一列和第三列(名字和年龄)
  • 只有特定范围内的行,例如,在上面的简单示例中,它将是第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>

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



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

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

吉姆
史密斯
34
罗伊
罗杰斯
22
并将XSLT中的行更改为:

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

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

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

1.
3.
在提供的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>

(信息…)
名字
姓
年龄
吉姆
史密斯
34
罗伊
罗杰斯
22
汉克
格朗迪耶
23
(信息…)
(信息…)
俏皮话
云彩
26
约翰
兰德尔
44
生成所需的正确结果:

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

吉姆
34
罗伊
22
汉克
23
俏皮话
26
约翰
44

+1:如果您没有更好的标准来选择行/列(例如,单元格上的有用属性或差异化元素名称),那就是您必须要做的。这很好,有没有办法将3,5,7,8放入“映射xml”中或者其他一些数据存储并用XSLT读取?@Edward Tanguay:您可以使用
,然后从调用XSLT转换的代码中注入参数值。这类代码可以在任何需要的地方采用参数值形式:mapping.xml、DB、GUI等。要在XPath表达式中使用参数,请记住在其名称前面加上
$
符号,例如
(position()=$param-name-1
@MarcoS:不需要在属性值中重新输入
字符。内容模板中的位置测试仅在上下文列表位置很重要(推送样式、排序)时有用,否则在选择XPath表达式时使用它更简单。最后:“Brick”模板是awful@Alejandro:about
编码:你是对的:我编辑了上面的XSL。about“内容模板内的位置测试”:你也是对的。我写道这不是很优雅,但这是我想出的最快的解决方案。而且,在这种情况下,我不确定如何使用
位置()
在一个正在选择的XPath表达式中。你能给我一个提示吗?好问题,+1。有关使用最基本的XSLT设计模式之一(覆盖标识规则)的完整、简短而简单的解决方案,请参阅我的答案。:+1好答案。在内容模板内进行验证时,可以使用常规
文档(“”)/*/my:params/行范围[$vPosition>=@start和@end>=$vPosition]