如何附加由XSLT多次嵌入生成的元素

时间:2019-04-29 06:08:41

标签: xml xslt

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

我的问题是Messages元素。

此元素是动态的,消息子元素的数量可以变化,并且取决于源XML的内容。

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

所以说,我有两个不同的模板来生成名为Temp1和temp2的Myelement1和Myelement2,因此我想在messages元素下添加一些消息(不是常量消息,可以是任何东西),而所应用的模板(temp1)是正在执行,然后在执行第二个模板(temp2)时再发送一些不同的消息(不是常量消息)。

例如 如果A不是数字,则应该是如下消息:

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

将message元素视为日志或错误元素。

感谢您的帮助。

2 个答案:

答案 0 :(得分: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上查看它的运行情况

答案 1 :(得分:1)

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

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>