【问题标题】:Match element N with certain name with element N of other XML when XSL mergingXSL 合并时,将具有特定名称的元素 N 与其他 XML 的元素 N 匹配
【发布时间】:2013-01-28 13:09:41
【问题描述】:

我有两个 XML 文档需要合并。

<!-- A.xml -->
<cm:Process>
    <cm:Other />
    <cm:Elements />
    <cm:Request>
        <!-- stuff -->
    </cm:Request>
    <cm:ElementCouldBeHereToo />
    <cm:Request>
        <!-- stuff -->
    </cm:Request>
</cm:Process>

<!-- B.xml -->
<gateway-orders>
    <response>
        <status />
    </response>
    <response>
        <status />
    </response>
</gateway-orders>

第一个是原始 XML。请求已被提取并发送到系统,接下来是响应。现在我需要合并这两个并将请求 N 与响应 N 匹配,以便我可以从响应中提取一些信息。 XSL 在 A.xml 上工作并将 B.xml 作为参数。首先,我只是尝试在 A.xml 中的请求中创建 B.xml 中正确响应的副本。

我的问题是我认为我可以使用position(),但意识到这不起作用,因为cm:Request 元素与其他元素混合在一起。有没有其他方法可以用来匹配这些?

这是我尝试过的:

<xsl:import href="identity-transform.xsl" />

<xsl:param name="responses" />


<xsl:template match="cm:Request">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
        <xsl:apply-templates select="$responses/*[1]/*[position()]" />
    </xsl:copy>
</xsl:template>

这里有两个问题。

  1. 首先position() 不匹配。有没有办法获取您所在的 cm:Request 元素的数量/位置,而不是所有兄弟元素的数量/位置?所以第一个 cm:Request 总是给出 1,不管它前面是否有任何元素。
  2. 其次,出于某种原因,我在每个请求中获取了所有响应的副本。如果我将position() 更改为例如1,我只会得到每个请求中第一个响应的副本。我在这里做错了什么?

希望有人知道我应该在这里做什么,因为我现在有点空白,我的 Google-fu 让我失望了:P

总结一下,如何将名称为blah 的第n 个元素与参数节点集中的第n 个子元素匹配?

【问题讨论】:

    标签: xml xslt xpath merge


    【解决方案1】:

    怎么样:

    <xsl:template match="cm:Request">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
            <xsl:variable name="reqNum" select="count(preceding-sibling::cm:Request | .)" />
            <xsl:apply-templates select="$responses/*[1]/response[$reqNum]" />
        </xsl:copy>
    </xsl:template>
    

    解释一下:

    2.其次,由于某种原因,我在每个请求中获取了所有响应的副本。如果我用例如 1 更改 position(),我只会得到每个请求中第一个响应的副本。我在这里做错了什么?

    在这种情况下,position() 实际上的行为与您想象的不同。如果您在该模板中执行此操作:

    <xsl:variable name="pos" select="position()" />
    

    那么 $pos 将具有当前cm:Request 相对于其所有兄弟的位置,但这里:

    $responses/*[1]/*[position()]
    

    position() 正在上下文 $responses/*[1]/* 中进行评估。因此,对于第一个 &lt;response&gt;,其计算结果为 $responses/*[1]/*[1],对于第二个响应,其计算结果为 $responses/*[1]/*[2],因此始终选择两者。

    【讨论】:

    • 有趣。您和@martin-honnen 的答案似乎都给出了相同的结果。他们之间有什么区别?似乎更准确,但不确定&lt;xsl:number/&gt; 给出的确切信息(除了在这种情况下它似乎返回相同)。
    • @Svish From the spec: 如果未指定count属性,则默认匹配与当前节点具有相同节点类型的任何节点的模式,如果当前节点有一个扩展名称,与当前节点具有相同的扩展名称。 换句话说,当&lt;xsl:number&gt; 不带属性使用时,它会产生与当前节点具有相同名称和命名空间的先前兄弟节点的数量节点,+1。
    • @Svish 换句话说,Martin 的示例和我的示例实际上以两种不同的方式执行完全相同的操作。我认为他的方法非常漂亮,这是我以前不知道的,尽管我的好处是在不知道&lt;xsl:number&gt; 的来龙去脉的情况下很清楚它的作用。所以我认为使用哪一个只是偏好问题。
    • 确实很漂亮!我想我会选择更短的版本,但我会接受你的,因为你也解释了另一个问题:)
    【解决方案2】:

    应该是一种方式

    <xsl:template match="cm:Request">
      <xsl:variable name="index"><xsl:number/></xsl:variable>
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
         <xsl:apply-templates select="$responses/*[1]/*[position() = $index]"/>
      </xsl:copy>
    </xsl:template>
    

    【讨论】:

    • &lt;xsl:number/&gt; 在这种情况下到底做了什么?它似乎给出了正确的结果,但不知道为什么:p
    • @JLRishe 想通了。谢谢!
    猜你喜欢
    • 2022-01-01
    • 2023-03-06
    • 2011-10-16
    • 2013-03-17
    • 2015-08-26
    • 1970-01-01
    • 2018-10-20
    • 2015-01-15
    • 1970-01-01
    相关资源
    最近更新 更多