XSLT,将id映射到新值

时间:2018-02-23 08:29:38

标签: xml xslt xslt-1.0

我搜索了所有xslt映射问题,但还没有找到解决我的具体案例的方法。

所以,假设这是我的源XML:

<Data>
  <A val='1'>
    <CC>1234</CC>
  </A>
  <A val='2'>
    <CC>1234</CC>
    <CC>5678</CC>
  </A>
  <A val='3'>
    <CC>1234</CC>
  </A>
  <B val='1'>
    <CC>5678</CC>
  </B>
  <B val='2'>
    <CC>1234</CC>
    <CC>9012</CC>
  </B>
</Data>

我想要的结果如下:

<Data>
  <A val='1'>
    <CC>-1</CC>
  </A>
  <A val='2'>
    <CC>-1</CC>
    <CC>-2</CC>
  </A>
  <A val='3'>
    <CC>-1</CC>
  </A>
  <B val='1'>
    <CC>-2</CC>
  </B>
  <B val='2'>
    <CC>-1</CC>
    <CC>-3</CC>
  </B>
</Data>

如果我用某种编程语言对它进行编码,我会首先将所有CC值放入一个集合/集合中,然后当我知道所有可能的CC值时,我会迭代整个集合并替换XML中的值使用在循环内减少的计数器。但我不知道如何在XSLT中做到这一点...... 所以在上面的例子中,我有CC值1234,5678和9012。 当迭代这些值时,所有具有1234的CC值应该变为-1,5678 ==&gt; -2和9012 ==&gt; -3 ,无论CC是在A还是B 。如果5678映射到-1,9012到-2和1234到-3也可以,但所有出现的1234必须更改为-3然后依此类推。 谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

假设您可以使用XSLT 2.0,您可以使用distinct-values获取CC的不同值,然后对于每个CC,您可以使用index-of来查找它在不同列表中的位置,并使用它来输出您想要的数字。

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

  <xsl:variable name="distinctCC" select="distinct-values(//CC)" />

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

  <xsl:template match="CC">
    <xsl:copy>
      <xsl:value-of select="0 - index-of($distinctCC, text())" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

如果你只能使用XSLT 1.0,那么你可以回到使用Muenchian Grouping来获得不同的值,尽管找到索引的工作也更多了。

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

  <xsl:key name="cc" match="CC" use="." />

  <xsl:variable name="distinctCC" select="//CC[generate-id() = generate-id(key('cc', .)[1])]" />

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

  <xsl:template match="CC">
    <xsl:copy>
      <xsl:variable name="current" select="text()" />
      <xsl:variable name="pos">
          <xsl:for-each select="$distinctCC">
              <xsl:if test="$current = ."><xsl:value-of select="position()" /></xsl:if>
          </xsl:for-each>
      </xsl:variable>
      <xsl:value-of select="0 - $pos" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:0)

你可以创建一个&#34;地图&#34;将所有distinct-values放在变量中,例如:

<xsl:variable name="CCcoll">
    <xsl:for-each select="distinct-values(//CC)">
        <CC><xsl:value-of select="."/></CC>
    </xsl:for-each>
</xsl:variable>

CC个节点添加标识模板和模板覆盖:

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

<xsl:template match="CC">
    <xsl:variable name="curr_CC" select="."/>
    <xsl:copy>
        <!-- here, you are matching the
             current value to the "map"
             and getting it's position -->
        <xsl:value-of select="concat('-', $CCcoll/CC[.=$curr_CC]/count(preceding-sibling::*) + 1)"/>
    </xsl:copy>
</xsl:template>

整个样式表如下:

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

    <xsl:variable name="CCcoll">
        <xsl:for-each select="distinct-values(//CC)">
            <CC><xsl:value-of select="."/></CC>
        </xsl:for-each>
    </xsl:variable>

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

    <xsl:template match="CC">
        <xsl:variable name="curr_CC" select="."/>
        <xsl:copy>
            <xsl:value-of select="concat('-', $CCcoll/CC[.=$curr_CC]/count(preceding-sibling::*) + 1)"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>