要创造什么?功能或模板或?

时间:2013-03-02 15:20:40

标签: xslt xslt-2.0 xpath-2.0

我遇到以下问题,请参阅代码示例:

<xsl:if test="/Document/test/id">
  <TEST1>
     <xsl:value-of select="/Document/test/id"/>
   </TEST1>
</xsl:if>

我有一个巨大的xslt脚本,有很多相同的代码。我想创建一个函数,但我一直都有错误。我问自己这是否是解决这个问题的正确解决方案。

为了使代码更易于维护,我想使用类似下面的内容。 这不是xslt语法因为我不知道如何,而是想知道我在寻找什么。

...
<xsl:something "TEST1", "/Document/test/id1" />
<xsl:something "TEST2", "/Document/test/id2" />
...

代码会更好的可读性和可维护性,虽然我不知道如何解决这个问题:-( 欢迎任何建议......

关心Dirk

2 个答案:

答案 0 :(得分:2)

此转化

<xsl:stylesheet version="2.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:my="my:my" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="/">
     <xsl:sequence select="my:test(xs:QName('Test1'), /*/test/id1/string())"/>
     <xsl:sequence select="my:test(xs:QName('Test2'), /*/test/id2/string())"/>
     <xsl:sequence select="my:test(xs:QName('Test3'), /*/test/id3/string())"/>
     <xsl:sequence select="my:test(xs:QName('Test4'), /*/test/id4/string())"/>
 </xsl:template>

 <xsl:function name="my:test">
   <xsl:param name="pName" as="xs:QName"/>
   <xsl:param name="pToPresent" as="item()?"/>

   <xsl:if test="$pToPresent">
     <xsl:element name="{$pName}">
             <xsl:sequence select="$pToPresent"/>
     </xsl:element>
   </xsl:if>
 </xsl:function>
</xsl:stylesheet>

应用于以下XML文档时:

<Document>
 <test>
  <id1>Some Id1</id1>
 </test>
 <test>
  <id2>Some Id2</id2>
 </test>
 <test>
  <id4>Some Id4</id4>
 </test>
</Document>

产生了想要的正确结果:

<Test1>Some Id1</Test1>
<Test2>Some Id2</Test2>
<Test4>Some Id4</Test4>

请注意

  1. my:test()的第一个参数声明为xs:QName类型,它保证name指令的xsl:element属性的值始终有效名称

  2. my:test()的第二个参数被非常松散地声明为item()?类型,这使我们可以自由地提供任何类型的项目(字符串或节点或元素,或......)并且确切地提供的内容将“按原样”再现。

答案 1 :(得分:2)

我认为这是你最接近的目标:

<xsl:stylesheet version="2.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:f="custom-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/">
    <CONTENT>
      <xsl:sequence select="f:rename('TEST1', /Document/test/id1)"/>
      <xsl:sequence select="f:rename('TEST2', /Document/test/id2)"/>
    </CONTENT>
  </xsl:template>

  <xsl:function name="f:rename">
    <xsl:param name="name" as="xs:string"/>
    <xsl:param name="toWrap" />

    <xsl:if test="$toWrap">
      <xsl:element name="{$name}">
        <xsl:value-of select="$toWrap"/>
      </xsl:element>
    </xsl:if>
  </xsl:function>
</xsl:stylesheet>

当在以下输入上运行时:

<Document>
  <test>
    <id1>Hello!</id1>
    <id2>Hello again!</id2>
  </test>
</Document>

产生的输出是:

<CONTENT>
   <TEST1>Hello!</TEST1>
   <TEST2>Hello again!</TEST2>
</CONTENT>

您也可以尝试这个,这有点冗长,但XSLT 1.0兼容:

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

  <xsl:template match="/">
    <CONTENT>
      <xsl:apply-templates select="/Document/test/id1" mode="rename">
        <xsl:with-param name="name" select="'TEST1'" />
      </xsl:apply-templates>
      <xsl:apply-templates select="/Document/test/id2" mode="rename">
        <xsl:with-param name="name" select="'TEST2'" />
      </xsl:apply-templates>
    </CONTENT>
  </xsl:template>

  <xsl:template match="@* | node()" mode="rename">
    <xsl:param name="name" />
    <xsl:element name="{$name}">
      <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

在上面的示例XML上运行时,会再次生成相同的输出。