使用XSLT将两个元素更改为单个元素

时间:2013-05-22 05:52:08

标签: xslt

我希望从<mo></mo><mo></mo>转换为<mfenced> .. </mfenced>。 样本输入如下:

示例XML:

<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://www.w3.org/1998/Math/MathML">
  <p>
    <math>
      <mi>sin</mi>
      <mo>(</mo>
      <mi>x</mi>
      <mi>y</mi>
      <mo>)</mo>
      <mo>=</mo>
      <mi>sin</mi>
      <mi>x</mi>
      <mi>sin</mi>
      <mi>y</mi>
    </math>
  </p>
</chapter>

XSLT 2.0尝试过:

<?xml version='1.0'?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:m="http://www.w3.org/1998/Math/MathML"
    xmlns="http://www.w3.org/1998/Math/MathML"
    exclude-result-prefixes="m">

  <xsl:output method="xml"/>

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

  <xsl:template match="m:mo">
    <xsl:if test="(.)='('">
      <mfenced><xsl:apply-templates select="following-sibling::*[(.)=')']" mode="copy"/>
      </mfenced>
    </xsl:if>
    <xsl:if test="(.)=')'"></xsl:if>
  </xsl:template>

  <xsl:template match="m:mo" mode="copy"/>

</xsl:stylesheet>

需要输出:

<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://www.w3.org/1998/Math/MathML">
  <p>
    <math>
      <mi>sin</mi>
      <mfenced>
        <mi>x</mi>
        <mi>y</mi>
      </mfenced>
      <mo>=</mo>
      <mi>sin</mi>
      <mi>x</mi>
      <mi>sin</mi>
      <mi>y</mi>
    </math>
  </p>
</chapter>

3 个答案:

答案 0 :(得分:1)

这是我用来将mo中的括号转换为mfenced的xslt。

它使用查找匹配括号的算法。

<?xml version='1.0'?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:m="http://www.w3.org/1998/Math/MathML"
    xmlns="http://www.w3.org/1998/Math/MathML"
    exclude-result-prefixes="m">

  <xsl:output method="xml"/>

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

<xsl:template match="m:mo[(.)='(']">
<xsl:variable name="brcount">
<xsl:value-of select="count(following-sibling::m:mo[(.)='(' or (.)=')'])"/>
</xsl:variable>
 <xsl:call-template name="for.oploop">
 <xsl:with-param name="i"><xsl:value-of select="'0'"/></xsl:with-param>
 <xsl:with-param name="j"><xsl:value-of select="'1'"/></xsl:with-param> 
 <xsl:with-param name="count"><xsl:value-of select="$brcount"/></xsl:with-param>
 <xsl:with-param name="stringop"><xsl:value-of select="'('"/></xsl:with-param> 
 <xsl:with-param name="stringcl"><xsl:value-of select="')'"/></xsl:with-param> 
 </xsl:call-template>
</xsl:template>

<xsl:template match="m:mo[(.)=')']">
<xsl:variable name="brcount">
<xsl:value-of select="count(preceding-sibling::m:mo[(.)='(' or (.)=')'])"/>
</xsl:variable>
 <xsl:call-template name="for.clloop">
 <xsl:with-param name="i"><xsl:value-of select="'0'"/></xsl:with-param>
 <xsl:with-param name="j"><xsl:value-of select="'1'"/></xsl:with-param> 
 <xsl:with-param name="count"><xsl:value-of select="$brcount"/></xsl:with-param>
 <xsl:with-param name="stringop"><xsl:value-of select="'('"/></xsl:with-param> 
 <xsl:with-param name="stringcl"><xsl:value-of select="')'"/></xsl:with-param>  
 </xsl:call-template>
</xsl:template>

<xsl:template match="m:mo[(.)='[']">
<xsl:variable name="brcount">
<xsl:value-of select="count(following-sibling::m:mo[(.)='[' or (.)=']'])"/>
</xsl:variable>
 <xsl:call-template name="for.oploop">
 <xsl:with-param name="i"><xsl:value-of select="'0'"/></xsl:with-param>
 <xsl:with-param name="j"><xsl:value-of select="'1'"/></xsl:with-param> 
 <xsl:with-param name="count"><xsl:value-of select="$brcount"/></xsl:with-param>
 <xsl:with-param name="stringop"><xsl:value-of select="'['"/></xsl:with-param> 
 <xsl:with-param name="stringcl"><xsl:value-of select="']'"/></xsl:with-param> 
 </xsl:call-template>
</xsl:template>

<xsl:template match="m:mo[(.)=']']">
<xsl:variable name="brcount">
<xsl:value-of select="count(preceding-sibling::m:mo[(.)='[' or (.)=']'])"/>
</xsl:variable>
 <xsl:call-template name="for.clloop">
 <xsl:with-param name="i"><xsl:value-of select="'0'"/></xsl:with-param>
 <xsl:with-param name="j"><xsl:value-of select="'1'"/></xsl:with-param> 
 <xsl:with-param name="count"><xsl:value-of select="$brcount"/></xsl:with-param>
 <xsl:with-param name="stringop"><xsl:value-of select="'['"/></xsl:with-param> 
 <xsl:with-param name="stringcl"><xsl:value-of select="']'"/></xsl:with-param>  
 </xsl:call-template>
</xsl:template>


<xsl:template name="for.oploop">
        <xsl:param name="i"      />
        <xsl:param name="j"      />        
        <xsl:param name="count"  />
        <xsl:param name="stringop"  />        
        <xsl:param name="stringcl"  />        
        <xsl:if test="$i = $count">        
        <xsl:if test="$j &gt; '0'">
            <xsl:text disable-output-escaping="yes">&lt;mfenced separators="" open="</xsl:text>
          <xsl:value-of select="$stringop"/>
          <xsl:text disable-output-escaping="yes">" close=""&gt;&lt;/mfenced&gt;</xsl:text>
        </xsl:if>          
        <xsl:if test="$j = '0'">
            <xsl:text disable-output-escaping="yes">&lt;mfenced separators="" open="</xsl:text>
          <xsl:value-of select="$stringop"/>
          <xsl:text disable-output-escaping="yes">" close="</xsl:text>
          <xsl:value-of select="$stringcl"/>
          <xsl:text disable-output-escaping="yes">"&gt;</xsl:text>        
        </xsl:if>  
        </xsl:if>
        <xsl:if test="$i &lt; $count">
                <xsl:choose>
                 <xsl:when test="$j = '0'">
            <xsl:text disable-output-escaping="yes">&lt;mfenced separators="" open="</xsl:text>
          <xsl:value-of select="$stringop"/>
          <xsl:text disable-output-escaping="yes">" close="</xsl:text>
          <xsl:value-of select="$stringcl"/>
          <xsl:text disable-output-escaping="yes">"&gt;</xsl:text>        
                 </xsl:when>
                 <xsl:otherwise>
                  <xsl:choose>
                   <xsl:when test="following-sibling::m:mo[(.)=$stringop or (.)=$stringcl][$i + 1] = $stringop">
                                    <xsl:call-template name="for.oploop">
                        <xsl:with-param name="i">
                                <xsl:value-of select="$i + 1"/>
                        </xsl:with-param>
                        <xsl:with-param name="j">
                                <xsl:value-of select="$j + 1"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="count">
                                <xsl:value-of select="$count"/>
                        </xsl:with-param>                                                
                        <xsl:with-param name="stringop"><xsl:value-of select="$stringop"/></xsl:with-param> 
                        <xsl:with-param name="stringcl"><xsl:value-of select="$stringcl"/></xsl:with-param>                                                 
                    </xsl:call-template>                
                   </xsl:when>
                   <xsl:when test="following-sibling::m:mo[(.)=$stringop or (.)=$stringcl][$i + 1] = $stringcl">
                                    <xsl:call-template name="for.oploop">
                        <xsl:with-param name="i">
                                <xsl:value-of select="$i + 1"/>
                        </xsl:with-param>
                        <xsl:with-param name="j">
                                <xsl:value-of select="$j - 1"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="count">
                                <xsl:value-of select="$count"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="stringop"><xsl:value-of select="$stringop"/></xsl:with-param> 
                        <xsl:with-param name="stringcl"><xsl:value-of select="$stringcl"/></xsl:with-param>                                                 
                    </xsl:call-template>                
                  </xsl:when>                
                  <xsl:otherwise/>
                  </xsl:choose>
                </xsl:otherwise>                
                </xsl:choose>
        </xsl:if>
</xsl:template>

<xsl:template name="for.clloop">
        <xsl:param name="i"      />
        <xsl:param name="j"      />        
        <xsl:param name="count"  />
        <xsl:param name="stringop"  />        
        <xsl:param name="stringcl"  />                
        <xsl:if test="$i = $count">
        <xsl:if test="$j &gt; '0'">
            <xsl:text disable-output-escaping="yes">&lt;mfenced separators="" open="" close="</xsl:text>
           <xsl:value-of select="$stringcl"/>
          <xsl:text disable-output-escaping="yes">"&gt;&lt;/mfenced&gt;</xsl:text>
        </xsl:if>          
        <xsl:if test="$j = '0'">
            <xsl:text disable-output-escaping="yes">&lt;/mfenced&gt;</xsl:text>
        </xsl:if>  
        </xsl:if>
        <xsl:if test="$i &lt; $count">
                <xsl:choose>
                 <xsl:when test="$j = '0'">
                                    <xsl:text disable-output-escaping="yes">&lt;/mfenced&gt;</xsl:text>
                 </xsl:when>
                 <xsl:otherwise>
                  <xsl:choose>
                   <xsl:when test="preceding-sibling::m:mo[(.)=$stringop or (.)=$stringcl][$i + 1] = $stringop">
                                    <xsl:call-template name="for.clloop">
                        <xsl:with-param name="i">
                                <xsl:value-of select="$i + 1"/>
                        </xsl:with-param>
                        <xsl:with-param name="j">
                                <xsl:value-of select="$j - 1"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="count">
                                <xsl:value-of select="$count"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="stringop"><xsl:value-of select="$stringop"/></xsl:with-param> 
                        <xsl:with-param name="stringcl"><xsl:value-of select="$stringcl"/></xsl:with-param>                                                                         
                    </xsl:call-template>                
                   </xsl:when>
                   <xsl:when test="preceding-sibling::m:mo[(.)=$stringop or (.)=$stringcl][$i + 1] = $stringcl">
                                    <xsl:call-template name="for.clloop">
                        <xsl:with-param name="i">
                                <xsl:value-of select="$i + 1"/>
                        </xsl:with-param>
                        <xsl:with-param name="j">
                                <xsl:value-of select="$j + 1"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="count">
                                <xsl:value-of select="$count"/>
                        </xsl:with-param>                        
                        <xsl:with-param name="stringop"><xsl:value-of select="$stringop"/></xsl:with-param> 
                        <xsl:with-param name="stringcl"><xsl:value-of select="$stringcl"/></xsl:with-param>                                                                         
                    </xsl:call-template>                
                  </xsl:when>                
                  <xsl:otherwise/>
                  </xsl:choose>
                </xsl:otherwise>                
                </xsl:choose>
        </xsl:if>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

这些Stack Overflow问题可能会有所帮助

您可以使用此模板将parent-with-child转换为组合元素:

<xsl:template match="parent">
  <combined>
    <xsl:copy-of select="@* | child/@*" />
  </combined>
</xsl:template>

这样做是将输入<parent>元素及其<child>中的所有属性复制到输出<combined>元素中。

您还需要身份模板,以便通过<data>元素和其他节点传递:

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

答案 2 :(得分:0)

这里有快速小脏解决方案 这也适用于嵌套大括号,但如果大括号在输入中不匹配,则会生成格式不正确的xml。 试试这个: &LT;

?xml version='1.0'?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:m="http://www.w3.org/1998/Math/MathML"
    xmlns="http://www.w3.org/1998/Math/MathML"
    exclude-result-prefixes="m">

    <xsl:output method="xml"/>

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

    <xsl:template match="m:mo[.=')']" >
        <xsl:text disable-output-escaping="yes"><![CDATA[</mfenced>]]></xsl:text>
    </xsl:template>

    <xsl:template match="m:mo[.='(']" >
        <xsl:text disable-output-escaping="yes"><![CDATA[<mfenced>]]></xsl:text>
    </xsl:template>
</xsl:stylesheet>