XSLT-遍历元素并转换为HTML

时间:2018-11-21 06:38:56

标签: xslt xslt-2.0 xslt-3.0

我的问题是遍历XML文件,找到变量1中提到的元素,并使用最简单的方法将它们替换为变量2中的元素。

示例XML

下面是示例XML文件:

 <?xml version="1.0" encoding="utf-8"?>
    <root>
    <figure id="f0005">
        <label>Fig. 1</label>
        <caption id="cn0005">
            <simple-para id="sp0015">Schematic diagram of the experimental setup.</simple-para>
        </caption>
    </figure>
    <figure id="f0010">
        <label>Fig. 2</label>
        <caption id="cn0010">
            <simple-para id="sp0020">Schematic drawing of the orifice plate.</simple-para>
        </caption>
    </figure>
</root>

使用此方法,我可以获得输出。但不是必需的输出标题中指定的那个。我认为我在样式表的for循环中做错了。请分享您的想法。

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="3.0">
    <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
    <xsl:variable name="els_element_name"
        select="tokenize('label simple-para figure caption', '\s+')"/>
    <xsl:variable name="html_element_name"
        select="tokenize('div div div div div', '\s+')"/>
    <xsl:template match="/">

        <xsl:for-each select="//element()"> 
            <xsl:variable name="ele_name" select="name()"/>
            <xsl:if test="index-of($els_element_name, $ele_name)">

                <xsl:variable name="array_val">
                    <xsl:value-of select="index-of($els_element_name, $ele_name)"/>
                </xsl:variable>

                <xsl:call-template name="optimized_code_start">
                    <xsl:with-param name="els_element" select="$ele_name"/>
                    <xsl:with-param name="position" select="$array_val"/>
                </xsl:call-template>

                <xsl:value-of select="."/>

                <xsl:call-template name="optimized_code_end">
                    <xsl:with-param name="els_element" select="$ele_name"/>
                    <xsl:with-param name="position" select="$array_val"/>
                </xsl:call-template>

            </xsl:if>

        </xsl:for-each>


    </xsl:template>



    <xsl:template name="optimized_code_start">
        <xsl:param name="els_element"/>
        <xsl:param name="position" as="xs:integer"/>
        <xsl:text disable-output-escaping="yes">&lt;</xsl:text>
        <xsl:value-of select="$html_element_name[$position]"/>
        <xsl:text disable-output-escaping="yes"> class="</xsl:text>
        <xsl:value-of select="$els_element"/>
        <xsl:text disable-output-escaping="yes">"</xsl:text>
        <xsl:for-each select="@*[(name()='id')]">
            <xsl:text disable-output-escaping="yes"> </xsl:text>
            <xsl:value-of select="name()"/>
            <xsl:text disable-output-escaping="yes">="</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text disable-output-escaping="yes">"</xsl:text>
        </xsl:for-each>
        <xsl:for-each select="@*[not(name()='id')]">
            <xsl:choose>
                <xsl:when test="name() = 'xml:lang'">
                    <xsl:text disable-output-escaping="yes"> </xsl:text>
                    <xsl:value-of select="name()"/>
                    <xsl:text disable-output-escaping="yes">="</xsl:text>
                    <xsl:value-of select="."/>
                    <xsl:text disable-output-escaping="yes">"</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:text disable-output-escaping="yes"> data-</xsl:text>
                    <xsl:value-of select="name()"/>
                    <xsl:text disable-output-escaping="yes">="</xsl:text>
                    <xsl:value-of select="."/>
                    <xsl:text disable-output-escaping="yes">"</xsl:text>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
        <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
    </xsl:template>


    <xsl:template name="optimized_code_end">
        <xsl:param name="els_element"/>
        <xsl:param name="position" as="xs:integer"/>
        <xsl:text disable-output-escaping="yes">&lt;/</xsl:text>
        <xsl:value-of select="$html_element_name[$position]"/>
        <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

必需的输出

我希望获得如下所述的输出。

    <html>
    <div class="figure" id="f0005">
    <div class="label">Fig. 1</div>
    <div class="caption" id="cn0005">
    <div class="simple-para" id="sp0015">Schematic diagram of the experimental setup.</div>
     </div>
    </div>
    <div class="figure" id="f0010">
    <div class="label">Fig. 2</div>
    <div class="caption" id="cn0010">
    <div class="simple-para" id="sp0020">Schematic drawing of the orifice plate. 
    </div>
    </div>
   </div>
   </html>

1 个答案:

答案 0 :(得分:1)

您可以简单地使用index-ofxsl:element进行匹配,并将输入名称映射到输出名称:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

   <xsl:variable name="els_element_name"
        select="tokenize('label simple-para figure caption', '\s+')"/>
    <xsl:variable name="html_element_name"
        select="tokenize('div div div div div', '\s+')"/>

  <xsl:template match="*[index-of($els_element_name, name()) > 0]">
      <xsl:element name="{$html_element_name[index-of($els_element_name, name(current()))]}">
          <xsl:apply-templates select="@*"/>
          <xsl:attribute name="class" select="name()"/>
          <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>  
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bdxtra/2

另一种可能的方法可能是创建一个实现映射的样式表,并使用transform函数直接在XSLT 3.0中运行它:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

  <xsl:variable name="stylesheet">
      <axsl:stylesheet version="3.0">
          <axsl:mode on-no-match="shallow-copy"/>
          <xsl:for-each select="$els_element_name">
              <axsl:template match="{.}">
                  <axsl:element name="{let $p := position() return $html_element_name[$p]}">
                      <axsl:apply-templates select="@*"/>
                      <axsl:attribute name="class" select="'{.}'"/>
                      <axsl:apply-templates/>
                  </axsl:element>
              </axsl:template>
          </xsl:for-each>
      </axsl:stylesheet>
  </xsl:variable>

  <xsl:variable name="els_element_name"
        select="tokenize('label simple-para figure caption', '\s+')"/>
  <xsl:variable name="html_element_name"
        select="tokenize('div div div div div', '\s+')"/>

  <xsl:output indent="yes"/>

  <xsl:template match="/">
      <xsl:sequence select="$stylesheet"/>
      <xsl:sequence
        select="transform(
                  map {
                    'stylesheet-node' : $stylesheet,
                    'source-node' : .
                  }
                )?output"/>
  </xsl:template> 

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bdxtra/4。对于实际用例,请删除或注释掉<xsl:sequence select="$stylesheet"/>行,但我保留了它以显示创建的样式表。