【问题标题】:XSLT v1.0 - TransformationXSLT v1.0 - 转换
【发布时间】:2012-07-18 10:57:51
【问题描述】:

我是使用 XSLT 的新手。我的要求最好通过代码来表达。我正在寻找关于是否有可能通过 XLST 实现我的要求的建议。我不是要求人们为我编写代码——尽管代码建议也会受到赞赏。我正在寻找指针,例如“我需要链接多个转换”。我正在使用 XSLT v1.0。

我有输入 XML;

<Input>
  <BarId>123</BarId>
  <BarName>myname</BarName>
  <FooName>dummy</FooName>
</Input>

...并且需要创建输出;

<Out>
  <Foos>
    <Foo>
      <Id>100</Id>
      <Name>dummy</Name>
    </Foo>
  </Foos>
  <Bars>
    <Bar>
      <Id>123</Id>
      <Name>myname</Name>
      <FooId>100</FooId>
    </Bar>
  </Bars>
</Out>

关键点:

创建 Foo 元素是我需要帮助的部分。

Foo 元素最先于 Bar 元素。

我并不太担心生成 Foo Id(即在上面的示例 100 中) - 我在这里有几个选项 - 但我猜在 Bar 上填充 FooId 的方法将取决于整体方法?

(ps. 为含糊的标题道歉 - 我会根据分辨率相应更新)

【问题讨论】:

  • 我认为您需要更多信息才能提出有用的信息。写一些你所拥有的东西并给你你想要的东西很容易,但它留下了问题,是否有多个输入、多个 foo、多个条。 FooId 的意义是什么,为什么它是一个元素而不是一个属性,这是必不可少的吗?等

标签: xslt xslt-1.0


【解决方案1】:

我假设您想为输入中的每个不同的FooName 输出一个具有唯一 ID 的 Foo 元素。为此,您可以使用Muenchian method:

首先,您将构建一个xsl:key,使用它您可以通过其内容快速检索FooName 元素。

<xsl:key name="FooNames" match="FooName" use="."/>

使用此键,您可以只处理每个 FooName 的第一个实例,从而获得一个不同的列表。在这里您可以使用generate-id() 函数来比较节点的身份。

<xsl:apply-templates select="//FooName
                             [generate-id() = 
                              generate-id(key('FooNames', .)[1])]"/>

对于生成标识符,如果您不关心生成的标识符可能因运行而异,您可以再次使用generate-id() 函数。

把它们放在一起:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="FooNames" match="FooName" use="."/>

  <xsl:template match="/">
    <Out>
      <Foos>
        <xsl:apply-templates select="//FooName[generate-id() = 
                                     generate-id(key('FooNames', .)[1])]"/>
      </Foos>
      <Bars>
        <xsl:apply-templates select="//Input"/>
      </Bars>
    </Out>
  </xsl:template>

  <xsl:template match="FooName">
    <Foo>
      <Id><xsl:value-of select="generate-id()"/></Id>
      <Name><xsl:value-of select="."/></Name>
    </Foo>
  </xsl:template>

  <xsl:template match="Input">
    <Bar>
      <Id><xsl:value-of select="BarId"/></Id>
      <Name><xsl:value-of select="BarName"/></Name>
      <FooId>
        <xsl:value-of select="generate-id(key('FooNames', FooName)[1])"/>
      </FooId>
    </Bar>
  </xsl:template>
</xsl:stylesheet>

使用以下示例输入:

<Inputs>
  <Input>
    <BarId>123</BarId>
    <BarName>myname</BarName>
    <FooName>dummy</FooName>
  </Input>
  <Input>
    <BarId>124</BarId>
    <BarName>anothername</BarName>
    <FooName>dummy</FooName>
  </Input>
  <Input>
    <BarId>125</BarId>
    <BarName>yetanothername</BarName>
    <FooName>dummy-two</FooName>
  </Input>
</Inputs>

它将产生输出:

<Out>
  <Foos>
    <Foo>
      <Id>id213296</Id>
      <Name>dummy</Name>
    </Foo>
    <Foo>
      <Id>id214097</Id>
      <Name>dummy-two</Name>
    </Foo>
  </Foos>
  <Bars>
    <Bar>
      <Id>123</Id>
      <Name>myname</Name>
      <FooId>id213296</FooId>
    </Bar>
    <Bar>
      <Id>124</Id>
      <Name>anothername</Name>
      <FooId>id213296</FooId>
    </Bar>
    <Bar>
      <Id>125</Id>
      <Name>yetanothername</Name>
      <FooId>id214097</FooId>
    </Bar>
  </Bars>
</Out>

【讨论】:

  • 谢谢尤卡。我已经对此进行了测试,它确实有效!感谢 NB 的支持文本/链接 - 让 v 清楚发生了什么。
【解决方案2】:

可以这么简单,假设 BarName 在其对应的 FooName 之前:

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

 <xsl:template match="/*">
     <Out>
      <Foos>
       <xsl:apply-templates select="FooName"/>
      </Foos>
      <Bars>
       <xsl:apply-templates select="BarName"/>
      </Bars>
     </Out>
 </xsl:template>

 <xsl:template match="FooName">
  <Foo>
    <Id><xsl:call-template name="makeFooId"/></Id>
    <Name><xsl:value-of select="."/></Name>
  </Foo>
 </xsl:template>
 <xsl:template match="BarName">
   <Bar>
    <Id><xsl:value-of select="preceding-sibling::BarId[1]"/></Id>
    <Name><xsl:value-of select="."/></Name>
    <FooId>
      <xsl:call-template name="makeFooId">
        <xsl:with-param name="pFoo" select="following-sibling::FooName[1]"/>
      </xsl:call-template>
    </FooId>
  </Bar>
 </xsl:template>

 <xsl:template name="makeFooId">
  <xsl:param name="pFoo" select="."/>

  <!-- Replace the following line with your id - generating code -->
  <xsl:text>100</xsl:text>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的 XML 文档时:

<Input>
    <BarId>123</BarId>
    <BarName>myname</BarName>
    <FooName>dummy</FooName>
</Input>

产生想要的正确结果

<Out>
   <Foos>
      <Foo>
         <Id>100</Id>
         <Name>dummy</Name>
      </Foo>
   </Foos>
   <Bars>
      <Bar>
         <Id>123</Id>
         <Name>myname</Name>
         <FooId>100</FooId>
      </Bar>
   </Bars>
</Out>

【讨论】:

  • 感谢您的帖子 Dimitre。 2 将此方法与 Jukka 的帖子进行比较很有用。
  • @Damo:Jukka 做了一些猜测,得出需要分组的结论。这可能是对的,也可能是错的。我不做任何猜测 - 只需使用问题中提供的信息。 Jukka any BarName 的另一个疯狂猜测应该与第一个唯一的 FooName 绑定——我认为这很可能是一个错误的假设。如果您的数据更具体,而不仅仅是真实数据的基本草图/投影,您将获得更准确的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 2019-10-06
  • 2018-09-08
  • 2019-12-21
相关资源
最近更新 更多