【问题标题】:XSL Modify element value from another elementXSL 从另一个元素修改元素值
【发布时间】:2018-09-28 12:20:10
【问题描述】:

我希望能够从元素 B 的模板中修改元素 A 的值

XML 输入

<Parent>
   <Elem1 Attr="Something" OtherAttr="Other">ExistingValue</Elem1>
   <Elem2 Attr="SomethingElse" />
</Parent>

XSL

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

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

<xsl:template match="Elem1">
   <!-- SOMEHOW MODIFY HERE VALUE OF ELEM2 -->
</xsl:template>
</xsl:stylesheet>

预期的 XML 输出

<Parent>
 <Elem1 Attr="Something" OtherAttr="Other">ExistingValue</Elem1>
 <Elem2 Attr="SomethingElse">Value from elem1</Elem2>
</Parent>

【问题讨论】:

  • 我不清楚您希望做什么。如果您有一个匹配Elem1 的模板并且想要处理Elem2 兄弟,那么您当然可以通过选择例如following-sibling::Elem2。不确定您希望对该元素做什么,除非您想中断已建立的处理并使用 xsl:for-each 或 (XSLT 3) xsl:copy-of select="following-sibling::Elem2" 处理它。
  • 您给出的示例没有显示从Elem1 数据中获取的任何值,并且您没有阻止Elem2 的基于身份的处理,所以我不确定您要在哪里以及为什么要中断正常处理。
  • 不要依赖 elem1 和 elem 2 是兄弟姐妹,它们可以在 xml 中的任何位置。我的观点是能够根据元素 1 的属性修改元素 2 的值,但它必须在 elem1 模板匹配中提供。现在清楚了吗?
  • 通常的方法是写一个xsl:template match="Elem2",然后从例如选择/拉取任何值。 //Elem1//Elem1/@foo.

标签: xml xslt xslt-1.0 xslt-2.0


【解决方案1】:

您不能在 XSLT 中“修改”事物。您的样式表将一个 XML 文档作为输入并生成另一个 XML 文档作为输出。最好将您的样式表视为按顺序编写输出,在生成每个结果元素时访问它需要构造每个结果元素的输入的任何部分。唯一可以设置元素 E 值的时间是在编写元素 E 时。(这是对正在发生的事情的过度时间化的描述,但它是一个有用的思维模型。)

在您的示例中,设置 Elem2 值的代码通常属于 Elem2 的模板规则。

【讨论】:

    【解决方案2】:

    这是一个想法。

    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Elem1">
      <!-- Write out Elem1. -->
      <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    
      <xsl:apply-templates select="//Elem2" mode="outElem2">
        <xsl:with-param name="Elem1Attr" select="@Attr"/>
        <!-- You could also pass the value from Elem1 here. -->
      </xsl:apply-templates>
    </xsl:template>
    
    <!-- Suppress Elem2-->
    <xsl:template match="Elem2"/>
    
    <!--**** outElem2 mode. -->  
    <xsl:template match="node() | @*" mode="outElem2">
      <xsl:param name="Elem1Attr"/>
      <xsl:copy>
        <xsl:apply-templates select="node() | @*" mode="outElem2">
          <xsl:with-param name="Elem1Attr" select="@Attr"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Elem2" mode="outElem2">
      <xsl:param name="Elem1Attr"/>
      <xsl:copy>
        <!-- Output the attributes. -->
        <xsl:apply-templates select="@*" mode="outElem2"/>
    
        <xsl:choose>
          <xsl:when test="$Elem1Attr = 'Something'">
            <xsl:value-of select="'Value from elem1'"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="'Something else'"/>
          </xsl:otherwise>
        </xsl:choose> 
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 太棒了!谢谢你。这正是我想要的。
    • 酷。您可以检查我的答案旁边的向上箭头来结束这个问题并给我分数吗?谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多