0

我在转换 XML 消息的某些元素时遇到问题。我需要交换一些值,但是在将最后一个节点的值复制到第一个节点后,我无法达到第一个节点的原始值。

我一直在寻找几个小时,并在我的 XSL 中尝试了几种变体,但没有一个能给出令人满意的结果。我不是一个很有经验的 XSL 程序员,但我相信解决方案不会那么困难。我简化了原始消息来解释问题,我希望你们中的一个可以帮助我解决这个问题。让我通过下面的例子来解释:

来源:

<ProcessMessages>
  <Message>
    <SomeNode>Val</SomeNode>
    <SomeNode>Val</SomeNode>
    <Number>100000</Number>
    <ExternalRefID>EXX12345600000001</ExternalRefID>
    <SomeNode>Val</SomeNode>
    <SomeNode>Val</SomeNode>
  </Message>
  <RelatedMessages>
    <Message>     
      <SomeNode>Val</SomeNode>
      <Number>200000</Number>
      <ExternalRefID>EXX12345600000002</ExternalRefID>
      <SomeNode>Val</SomeNode>
    </Message>
    <Message>
      <SomeNode>Val</SomeNode>
      <Number>300000</Number>
      <ExternalRefID>EXX12345600000003</ExternalRefID>
      <SomeNode>Val</SomeNode>
    </Message>
  </RelatedMessages>
</ProcessMessages>

期望的转变:

<ProcessMessages>
  <Message>
    <SomeNode>Val</SomeNode>
    <SomeNode>Val</SomeNode>
    <ExternalRefID>EXX12345600000003</ExternalRefID>
    <SomeNode>Val</SomeNode>
    <SomeNode>Val</SomeNode>
  </Message>
  <RelatedMessages>
    <Message>     
      <Number>200000</Number>
      <ExternalRefID>EXX12345600000002</ExternalRefID>
    </Message>
    <Message>
      <Number>100000</Number>
      <ExternalRefID>EXX12345600000001</ExternalRefID>
    </Message>
  </RelatedMessages>
</ProcessMessages>

我的 XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

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

<xsl:template match="//ProcessMessages/Message/ExternalRefID">
    <xsl:apply-templates select="//ProcessMessages/RelatedMessages/Message[last()]/ExternalRefID"/>
  </xsl:template>
  <xsl:template match="//ProcessMessages/Message/Number">
    <xsl:apply-templates select="//ProcessMessages/RelatedMessages/Message[last()]/Number"/>
  </xsl:template>

  <xsl:template match="//ProcessMessages/RelatedMessages/Message[1]">
    <xsl:element name="Message">
      <xsl:apply-templates select="ExternalRefID"/>
      <xsl:apply-templates select="Number"/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="//ProcessMessages/RelatedMessages/Message[2]">
    <xsl:element name="Message">
      <xsl:apply-templates select="//ProcessMessages/Message/ExternalRefID"/>
      <xsl:apply-templates select="//ProcessMessages/Message/Number"/>
    </xsl:element>
  </xsl:template>  
</xsl:stylesheet>

当前结果

<ProcessMessages>
  <Message>
    <SomeNode>Val</SomeNode>
    <SomeNode>Val</SomeNode>
    <Number>100000</Number>
    <ExternalRefID>EXX12345600000001</ExternalRefID>
    <SomeNode>Val</SomeNode>
    <SomeNode>Val</SomeNode>
  </Message>
  <RelatedMessages>
    <Message>
      <ExternalRefID>EXX12345600000002</ExternalRefID>
      <Number>200000</Number>
    </Message>
    <Message>
      <ExternalRefID>EXX12345600000001</ExternalRefID>
      <Number>100000</Number>
    </Message>
  </RelatedMessages>
</ProcessMessages>

请注意,将 的值复制到后,ProcessMessages/RelatedMessages/MessageProcessMessages/Message无法达到默认值,ProcessMessages/Message因为它似乎被覆盖了。

有任何想法吗?如果有人可以帮助我,我将不胜感激!

4

1 回答 1

0

不,您没有覆盖输入中的任何内容。XSLT 转换的输出树是与输入分开的对象,并且输入是不可变的。输入中的任何内容都不会被覆盖或更改。

是的,你是对的:你的问题有一个简单的解决方案。

问题是您尝试将 ExternalRefID 和 Number of /ProcessMessages/Message 复制到 RelatedMessages 元素的末尾采用以下形式:

<xsl:apply-templates 
  select="//ProcessMessages
           /Message/ExternalRefID"/>
<xsl:apply-templates 
  select="//ProcessMessages
           /Message/Number"/>

样式表引擎按照您的要求进行操作,并为这些元素寻找模板。它在您的示例代码中找到第二个和第三个模板,这些模板从相关消息中的最后一个消息元素中查找和复制值。

我并不完全清楚如何定义您要构建的转换,但如果您尝试做的是(1)将 RelatedMessages 的最终消息移动为 ProcessMessages 的第一个孩子,以及(2)将 ProcessMessages 的第一个孩子移动到 RelatedMessages 的末尾,然后这样的事情会起作用:

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

<xsl:template match="ProcessMessages">
  <xsl:copy-of 
    select="RelatedMessages/Message[last()]"/>
  <xsl:apply-templates select="RelatedMessages"/>
</xsl:template>

<xsl:template 
  match="RelatedMessages/Message[last()]">
  <xsl:copy-of 
    select="../../self::ProcessMessages
            /Message[1]"/>
</xsl:template>  

如果您只想更改Number 和 ExternalRefID,则需要适当地修改此代码。

于 2012-09-20T23:15:53.393 回答