【问题标题】:How to append an element which is generated embedded by an XSLT multiple times如何附加由 XSLT 多次嵌入生成的元素
【发布时间】:2019-04-29 06:08:41
【问题描述】:

使用 XSLT 1.0:

我有以下 xml 作为输入

<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <Sub1>
      <Val1>A</Val1>
      <Val3>C</Val3>
  </Sub1>
  <Sub2>
      <Val2>NIL</Val2>
    <Val4>D</Val4>
  </Sub2>
</Root>

还有我的 XSLT:

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


  <xsl:template match="/Root">

    <xsl:element name ="New">

      <xsl:apply-templates select="Sub1"/>

      <xsl:apply-templates select="Sub2"/>

    </xsl:element>


  </xsl:template>

  <xsl:template match="Sub1" >
    <xsl:variable name='pr' select='.'/>

    <xsl:element name="Myelement1"  >
      <!-- The value should be added to the output regardless-->
      <xsl:value-of select="$pr/Val1"/>

      <xsl:if test="number($pr/Val1) = $pr/Val1">

        <!--TWO things should be done:
    1- Check if     <messages> is created in the output XML? if not it should be created
    2- A message Should be added to     <Messages> like     <Message> Myelement1 is not numeric    </Message>--> 

      </xsl:if>
    </xsl:element>
  </xsl:template>


  <xsl:template match="Sub2" >
      <xsl:variable name='pr' select='.'/>

      <xsl:element name="Myelement2"  >
        <!-- The value should be added to the output regardless-->
        <xsl:value-of select="$pr/Val2"/>

        <xsl:if test="$pr/Val2='NIL'">

          <!--TWO things should be done:
      1- Check if     <messages> is created in the output XML? if not it should be created
      2- A message Should be added to     <Messages> like     <Message> Myelement2 is not valid    </Message>-->

        </xsl:if>
      </xsl:element>

  </xsl:template>

</xsl:stylesheet>

当前 XSLT 生成以下输出:

<?xml version="1.0" encoding="utf-8"?>
<New>
  <Myelement1>A</Myelement1>
  <Myelement2>NIL</Myelement2>
</New>

但这是我真正想要的:

 <?xml version="1.0" encoding="utf-8"?>
 <New>
    <Myelement1>A</Myelement1>
    <Myelement2>NIL</Myelement2>

   <Messages>
     <Message> Myelement1 is not numeric </Message>
     <Message> Myelement2 is not valid </Message>
   </Messages>
 </New>

我的问题是消息元素。

此元素是动态的,消息子元素的数量可能会有所不同,并且取决于源 XML 的内容。

它也可能是空的,但最大的问题是我想在运行时添加这些消息子元素,而 XSLT 正在使用多个模板等浏览源 xml 文件。

假设我有两个不同的模板来生成名为 Temp1 和 temp2 的 Myelement1 和 Myelement2,所以我想在消息元素下添加一些消息(不是常量消息,可以是任何东西),而应用的模板 (temp1) 是正在执行,然后在执行第二个模板 (temp2) 时会收到更多不同的消息(不是恒定消息)。

例如 如果 A 不是数字,则应在消息下添加如下消息

<message> myelement1 is not in a correct format < Message>

将消息元素视为日志或错误元素。

感谢您的帮助。

【问题讨论】:

  • 抱歉,这还不清楚。您需要更详细地解释,使用示例 XML 和 XSL&lt;Message&gt; 元素是如何生成的。
  • @JimGarrison 刚刚添加了一个例子
  • 这很好,但它是如何生成的?添加消息的决定在哪里?
  • @JimGarrison ,我再次更新了问题。希望这一次,很清楚
  • 如果我正确理解了您的问题 (?),您需要分两步执行此操作:首先,让您的模板写入变量。然后处理变量(将其转换为节点集后)并将两组消息合并为一组。要么改变你的整体方法。我不知道有一种方法可以让模板写入输出中的两个不同位置。

标签: xml xslt


【解决方案1】:

您可以分两次执行此操作。在第一遍中,您可以将结果存储在一个变量中,其中 Message 元素只是在您创建或更改任何新元素之后创建。

然后在第二遍中,您可以简单地更改任何存在的 Message 元素的位置,尽管在 XSLT 1.0 中您必须使用 node-set 扩展函数来执行此操作,作为您创建的变量举行第一关将是一个“结果树片段”。 exslt 节点集函数得到了广泛的支持,所以你应该可以使用它。

试试这个 XSLT

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

  <xsl:template match="/Root">
    <xsl:variable name="pass1">
      <xsl:element name ="New">
        <xsl:apply-templates select="Sub1"/>
        <xsl:apply-templates select="Sub2"/>
      </xsl:element>
    </xsl:variable>
    <xsl:apply-templates select="exslt:node-set($pass1)" xmlns:exslt="http://exslt.org/common" mode="pass2" />
  </xsl:template>

  <xsl:template match="Sub1" >
    <xsl:variable name='pr' select='.'/>
    <xsl:element name="Myelement1"  >
       <xsl:value-of select="$pr/Val1"/>
    </xsl:element>
    <xsl:if test="not(number($pr/Val1) = $pr/Val1)">
      <Message>Myelement1 is not numeric</Message>
    </xsl:if>
  </xsl:template>

  <xsl:template match="Sub2" >
    <xsl:variable name='pr' select='.'/>
    <xsl:element name="Myelement2"  >
      <xsl:value-of select="$pr/Val2"/>
    </xsl:element>
    <xsl:if test="$pr/Val2='NIL'">
      <Message>Myelement2 is not valid</Message>
    </xsl:if>
  </xsl:template>

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

  <xsl:template match="New[Message]" mode="pass2">
    <xsl:copy>
      <xsl:apply-templates select="node()[not(self::Message)]" mode="pass2" />
      <Messages>
         <xsl:apply-templates select="Message" mode="pass2" />
      </Messages>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/6r5Gh3t查看它的实际应用

【讨论】:

    【解决方案2】:

    另一种方法是为输出的每个部分使用单独的模板。考虑以下简化示例:

    XML

    <root>
        <elemA>alpha</elemA>
        <elemB>55</elemB>
    </root>
    

    XSLT 1.0

    <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:template match="/root">
        <output>
            <xsl:apply-templates select="elemA | elemB"/>
            <Messages>
                <xsl:apply-templates select="elemA | elemB" mode="messages"/>        
            </Messages>
        </output>
    </xsl:template>
    
    <xsl:template match="elemA">
        <Myelement1>
            <xsl:value-of select="." />
        </Myelement1>
    </xsl:template>
    
    <xsl:template match="elemB">
        <Myelement2>
            <xsl:value-of select="." />
        </Myelement2>
    </xsl:template>
    
    <xsl:template match="elemA" mode="messages">
        <xsl:if test="not(number(.)=number(.))">
            <Message>Myelement1 is not a number.</Message>
         </xsl:if>
    </xsl:template>
    
    <xsl:template match="elemB" mode="messages">
        <xsl:if test=". > 50">
            <Message>Myelement2 is greater than 50.</Message>
         </xsl:if>
    </xsl:template>
    
    </xsl:stylesheet>
    

    结果

    <?xml version="1.0" encoding="UTF-8"?>
    <output>
      <Myelement1>alpha</Myelement1>
      <Myelement2>55</Myelement2>
      <Messages>
        <Message>Myelement1 is not a number.</Message>
        <Message>Myelement2 is greater than 50.</Message>
      </Messages>
    </output>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多