在 XSLT 中,如何插入适用于不同模板的匹配标签

发布于 2024-11-08 20:49:39 字数 1776 浏览 0 评论 0原文

我对 XSLT 很陌生,只是还没有找到解决我的问题的方法。我有一个看起来像这样的 xml 文件(我无法改变这个 xml 的外观,意识到它有点奇怪):

<account>
    <name>accountA</name>
</account>
<period>
    <type>priormonth</type>
</period>
<period>
    <type>currentmonth</type>
</period>
<account>
    <name>accountB</name>
</account>
<period>
    <type>priormonth</type>
</period>
<period>
    <type>currentmonth</type>
</period>

xml 文件可以有可变数量的帐户/期间/期间数据集但它们总是按这个顺序。

我有一个 xsl 文件,如下所示:

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

<xsl:template match="account">
    <name> <xsl:value-of select="name"/> </name>
</xsl:template>

<xsl:template match="period">
    <type> <xsl:value-of select="type"/> </type>
</xsl:template>

上面的效果很好,因为它处理多个帐户/期间/期间的出现,我的输出如下:

<name>accountA</name>
<type>priormonth</type>
<type>currentmonth</type>
<name>accountB</name>
<type>priormonth</type>
<type>currentmonth</type>

但是,我想要插入一些附加标签,以便输出实际上看起来像:

<account>
    <name>accountA</name>
    <period>
        <type>priormonth</type>
        <type>currentmonth</type>
    </period>
</account>
<account>
    <name>accountB</name>
    <period>
        <type>priormonth</type>
        <type>currentmonth</type>
    </period>
</account>

有办法做到这一点吗?如果我的术语不太正确,请道歉。 谢谢

I'm very new to XSLT and just haven't been able to find a solution yet to my problem. I have an xml file that looks like (and I can't change the way this xml looks, realizing it's a bit odd):

<account>
    <name>accountA</name>
</account>
<period>
    <type>priormonth</type>
</period>
<period>
    <type>currentmonth</type>
</period>
<account>
    <name>accountB</name>
</account>
<period>
    <type>priormonth</type>
</period>
<period>
    <type>currentmonth</type>
</period>

The xml file can have a variable number of account/period/period datasets but they are always in that order.

I've got an xsl file which looks like:

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

<xsl:template match="account">
    <name> <xsl:value-of select="name"/> </name>
</xsl:template>

<xsl:template match="period">
    <type> <xsl:value-of select="type"/> </type>
</xsl:template>

The above works great because it deals with the multiple account/period/period occurrences and my output comes out like:

<name>accountA</name>
<type>priormonth</type>
<type>currentmonth</type>
<name>accountB</name>
<type>priormonth</type>
<type>currentmonth</type>

However, I'm wanting to have some additional tags inserted so that the output actually looks like:

<account>
    <name>accountA</name>
    <period>
        <type>priormonth</type>
        <type>currentmonth</type>
    </period>
</account>
<account>
    <name>accountB</name>
    <period>
        <type>priormonth</type>
        <type>currentmonth</type>
    </period>
</account>

Is there a way of doing this? Apologies if my terminology is not quite right.
Thanks

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

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

发布评论

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

评论(2

雪若未夕 2024-11-15 20:49:39

试试这个:

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

  <xsl:template match="account">
    <xsl:copy>
      <xsl:apply-templates />
      <period>
        <xsl:apply-templates select="following-sibling::period[generate-id(preceding-sibling::account[1]) = generate-id(current())]/*" />
      </period>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="period" />

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

select 语句有点复杂,但它的基本作用是选择每个 account 元素后面的所有 period 同级,其中第一个 account 前面的元素是当前元素。

Try this:

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

  <xsl:template match="account">
    <xsl:copy>
      <xsl:apply-templates />
      <period>
        <xsl:apply-templates select="following-sibling::period[generate-id(preceding-sibling::account[1]) = generate-id(current())]/*" />
      </period>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="period" />

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

The select statement is a bit convoluted, but what it basically does it select all period siblings following each account element, where the first account element that precedes it is the current one.

香橙ぽ 2024-11-15 20:49:39

以下 XSLT 假定 xml 源与您的问题中所呈现的完全相同(除了缺少根导致源文档格式不正确)。在这种情况下,您不需要身份转换。此外,如果您的帐户确实只需要前两个句点,您可以使用更简单的 XPath。


XSLT 1.0Saxon-HE 9.2.1.1J 下测试

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

    <xsl:template match="/root">
        <xsl:copy>
            <xsl:apply-templates select="account"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="account">
        <xsl:copy>
            <xsl:copy-of select="name" />
            <period>
                <xsl:copy-of select="following-sibling::period[position()<=2]/type" />
            </period>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="period" />

</xsl:stylesheet>

应用于此输入:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
    <account>
        <name>accountA</name>
    </account>
    <period>
        <type>march</type>
    </period>
    <period>
        <type>currentmonth</type>
    </period>
    <account>
        <name>accountB</name>
    </account>
    <period>
        <type>priormonth</type>
    </period>
    <period>
        <type>currentmonth</type>
    </period>
</root>

给出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <account>
      <name>accountA</name>
      <period>
         <type>march</type>
         <type>currentmonth</type>
      </period>
   </account>
   <account>
      <name>accountB</name>
      <period>
         <type>priormonth</type>
         <type>currentmonth</type>
      </period>
   </account>
</root>

The following XSLT assumes that the xml source is exactly as presented in your question (apart the missing root which makes the source document not well formed). In this case you do not need identity transform. Moreover, if really your account needs only the first next two period you can use a simpler XPath.


XSLT 1.0 tested under Saxon-HE 9.2.1.1J

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

    <xsl:template match="/root">
        <xsl:copy>
            <xsl:apply-templates select="account"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="account">
        <xsl:copy>
            <xsl:copy-of select="name" />
            <period>
                <xsl:copy-of select="following-sibling::period[position()<=2]/type" />
            </period>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="period" />

</xsl:stylesheet>

Applied on this input:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
    <account>
        <name>accountA</name>
    </account>
    <period>
        <type>march</type>
    </period>
    <period>
        <type>currentmonth</type>
    </period>
    <account>
        <name>accountB</name>
    </account>
    <period>
        <type>priormonth</type>
    </period>
    <period>
        <type>currentmonth</type>
    </period>
</root>

Gives:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <account>
      <name>accountA</name>
      <period>
         <type>march</type>
         <type>currentmonth</type>
      </period>
   </account>
   <account>
      <name>accountB</name>
      <period>
         <type>priormonth</type>
         <type>currentmonth</type>
      </period>
   </account>
</root>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文