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

发布于 2024-10-21 13:32:42 字数 3399 浏览 2 评论 0原文

我如何使用 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 关于参数的提示:

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

How can I use XSLT to convert this XML file:

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

to this XML 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>

Basically the rules are:

  • only first and third column (first name and age)
  • only rows within certain ranges, e.g. in the simple example above it would be rows 3-5 and rows 7-8 so I would assume I would need some kind of mapping table with this information in it

Addendum

Here is my solution using MarcoS's tip about 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() >= $range-1-begin and position() <= $range-1-end)
                    or (position() >= $range-2-begin and position() <= $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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜未央樱花落 2024-10-28 13:32:42

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

<?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() < 5)
                    or (position() >= 7 and position() <= 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 的范围> 您想要的元素。

This is a possible solution (maybe not very elegant):

<?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() < 5)
                    or (position() >= 7 and position() <= 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>

Essentially, you can use XPath position() function to select the ranges of row and cell elements that you want.

猫弦 2024-10-28 13:32:42

这是执行您所描述的操作的 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()>=3 and position()<=5) or (position()>=7 and position()<=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 方法来执行此操作。例如,保留 Jim Smith 但放弃 Roy Rogers:

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

Here's a piece of XSLT that does what you describe.

<?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()>=3 and position()<=5) or (position()>=7 and position()<=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>

To select the rows you want in your output, I think I'd begin by marking them with an attribute which would be used as a filter.
In the code invoking the XSLT, you could do it using DOM methods just after loading the XML document and before applying the transformation. Eg to keep Jim Smith but discard Roy Rogers:

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

And change the line in the XSLT to:

<xsl:apply-templates select="row[@keep=-1]" />
划一舟意中人 2024-10-28 13:32:42

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

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

This is probably the simplest and shortest solution, also based on using and overriding the identity rule:

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

When this transformation is applied on the provided XML document:

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

the wanted, correct result is produced:

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文