【问题标题】:XSLT, mapping id's to new valuesXSLT,将 id 映射到新值
【发布时间】:2018-02-23 08:29:37
【问题描述】:

我已经搜索了所有 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 ==> -2 和 9012 ==>-3 无论 CC 是在 A 还是 B 之下强>。如果 5678 映射到 -1、9012 映射到 -2 和 1234 映射到 -3 也可以,但是 1234 的所有 出现必须更改为 -3,依此类推。 感谢您的帮助!

【问题讨论】:

  • 请解释确定新 CC 值背后的逻辑,因为简单地减少一个计数器不会导致一个序列,例如-1,-3 用于最后一个B 或以-2 开头的序列用于第一个B
  • 您确实需要将 XSLT 问题标记为 XSLT 1.0、2.0 或 3.0,因为除了最简单的问题之外,解决方案可能完全不同,如果您提供 2.0 的解决方案,那是浪费时间您必须使用 1.0(如果您可以使用 2.0,那么创建 1.0 解决方案会更加浪费时间)。

标签: xml xslt xslt-1.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>

【讨论】:

  • 我收到以下错误:错误:'样式表无法编译'。这是否意味着我正在使用 XSLT 1.0?如果是这样,我该如何改变?我正在使用 Java8
  • 要在 Java 中使用 XSLT 2.0,请参阅 stackoverflow.com/questions/41317022/…
【解决方案2】:

您可以通过将所有不同的值放在一个变量中来创建一个“映射”,例如:

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

【讨论】:

  • 不幸的是,在 Java 中使用它时会产生错误: ERROR: 'Syntax error in "concat('-', $CCcoll/CC[.=$curr_CC]/count(preceding-sibling:: *)+ 1)“。”致命错误:'file:/C:/devel/Workspaces/Misc/XSLT/ccstylesheet1.xslt:第 23 行:缺少属性“select”。'
猜你喜欢
  • 2021-04-12
  • 2020-08-09
  • 2018-05-16
  • 1970-01-01
  • 2011-03-19
  • 2019-07-21
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多