xslt转换xml元素中的xml字符串

xslt转换xml元素中的xml字符串,xslt,Xslt,这是一个棘手的问题 我有以下XML <test> <testElement SomeAttribute="<otherxml><otherElement>test test</otherElement></otherxml>"> </testElement> </test> 使用XSLT,我希望将此XML转换为以下结果 <test> <testE

这是一个棘手的问题

我有以下XML

<test>
     <testElement SomeAttribute="<otherxml><otherElement>test test</otherElement></otherxml>">
      </testElement>
</test>

使用XSLT,我希望将此XML转换为以下结果

<test>
     <testElement>
        <SomeAttributeTransformedToElement>
          <otherxml>
               <otherElement>test test</otherElement>
          </otherxml>
        </SomeAttributeTransformedToElement>
      </testElement>
</test>

测试
基本上,属性中的某些文本必须转换为最终XML中的实际元素

如何在XSLT中实现这一点


Alex

您可以通过禁用输出转义来实现这一点。但是,请注意,您的输入文档不是有效的XML文档(

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="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@SomeAttribute">
    <SomeAttributeTransformedToElement>
      <xsl:value-of select="." disable-output-escaping="yes"/>
    </SomeAttributeTransformedToElement>
  </xsl:template>
</xsl:stylesheet>


请注意,使用
disable output escaping=“yes”
不再保证生成的输出文档是格式良好的XML文档。

我也有同样的需求,我最终成功地构建了一些工作

然而,这还远远不够完美。但是,由于这个解决方案对我很有效(在我的案例中非常有用),我将它提供给任何可能被询问的人

我希望XSL纯粹主义者会原谅我这样做:

此XSLT命名模板将文本变量作为输入,并在输出上生成XML元素。 警告:存在一些限制:

  • XML不能有自包含的元素(…被禁止,因为“a”元素包含另一个“a”)
  • XML必须规范化(元素名和属性之间只有一个空格,所以是允许的,但不允许(这是可以修复的)
  • <element/>样式尚未处理(很抱歉,我不需要它,而且我正在忙于当前的项目),但这很容易修复
所以你已经被警告:在测试之前,不要把它投入生产,并确保它对你的情况难以辨认。此外,如果你碰巧修复或改进了这个脚本,请让我知道

以下是模板:

<xsl:template name="t-convert">
    <xsl:param name="TEXT"/>
    <xsl:choose>
        <xsl:when test="starts-with($TEXT,'&lt;?')">
            <xsl:call-template name="t-convert">
                <xsl:with-param name="TEXT" select="substring-after($TEXT,'?&gt;')"/>
            </xsl:call-template>
        </xsl:when>
        <!-- Si le texte contient encore des elements -->
        <xsl:when test="contains($TEXT,'&lt;')">
            <xsl:variable name="before-first-open" select="substring-before($TEXT,'&lt;')"/>
            <xsl:variable name="after-first-open" select="substring-after($TEXT,'&lt;')"/>
            <!-- On ecrit le texte qui précéde l'élément -->
            <xsl:value-of select="$before-first-open"/>
            <!-- Le nom de l'élément -->
            <xsl:variable name="TRAD" select="translate($after-first-open,'&gt;',' ')"/>
            <!--  TODO : Gere le cas <ELEMENT />   -->
            <xsl:variable name="ELEMENT" select="substring-before($TRAD,' ')"/>
            <xsl:variable name="suite" select="substring-after($after-first-open,$ELEMENT)"/>
            <xsl:variable name="DEFINITION" select="substring-before($suite,'&gt;')"/>
            <xsl:variable name="CONTENT" select="substring-after(substring-before($suite,concat('&lt;/',$ELEMENT)),concat($DEFINITION,'&gt;'))"/>
            <xsl:variable name="FOLLOWING">
                <xsl:choose>
                    <xsl:when test="substring($DEFINITION,string-length($DEFINITION))='/'"><!--  ends-with($DEFINITION,'/') not compatible with all XSLT version -->
                        <xsl:value-of select="substring-after($suite,'/&gt;')"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="substring-after(substring-after($suite,concat('&lt;/',$ELEMENT)),'&gt;')"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:element name="{$ELEMENT}">
                <xsl:call-template name="t-attribs">
                    <xsl:with-param name="TEXT" select="$DEFINITION"/>
                </xsl:call-template>
                <xsl:call-template name="t-convert">
                    <xsl:with-param name="TEXT" select="$CONTENT"/>
                </xsl:call-template>
            </xsl:element>
            <xsl:call-template name="t-convert">
                <xsl:with-param name="TEXT" select="$FOLLOWING"/>
            </xsl:call-template>
        </xsl:when>
        <!-- no more element -->
        <xsl:otherwise>
            <xsl:value-of select="$TEXT"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="t-attribs">
    <xsl:param name="TEXT"/>
    <xsl:if test="contains($TEXT,'=')">
        <!-- Assert TEXT=' NAME="VALUE".*' -->
        <xsl:variable name="NAME" select="substring-after(substring-before($TEXT,'='),' ')"/>
        <xsl:variable name="afterName" select="substring-after($TEXT,'=&quot;')"/>
        <xsl:variable name="VALUE" select="substring-before($afterName,'&quot;')"/>
        <xsl:variable name="FOLLOWING" select="substring-after($afterName,'&quot;')"/>
        <xsl:attribute name="{$NAME}">
            <xsl:value-of select="$VALUE"/>
        </xsl:attribute>
        <xsl:call-template name="t-attribs">
            <xsl:with-param name="TEXT" select="FOLLOWING"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>


好的,我知道,但是你明白了。属性中的字符串实际上是转义的:otherxml>otherElement>test/otherElement>/otherxml>+1正确答案。除此之外,只有一个解析器。而且,到目前为止,不需要这样的编码字符串,因为每个主要的数据库引擎都正确地支持XML。
<xsl:template name="t-convert">
    <xsl:param name="TEXT"/>
    <xsl:choose>
        <xsl:when test="starts-with($TEXT,'&lt;?')">
            <xsl:call-template name="t-convert">
                <xsl:with-param name="TEXT" select="substring-after($TEXT,'?&gt;')"/>
            </xsl:call-template>
        </xsl:when>
        <!-- Si le texte contient encore des elements -->
        <xsl:when test="contains($TEXT,'&lt;')">
            <xsl:variable name="before-first-open" select="substring-before($TEXT,'&lt;')"/>
            <xsl:variable name="after-first-open" select="substring-after($TEXT,'&lt;')"/>
            <!-- On ecrit le texte qui précéde l'élément -->
            <xsl:value-of select="$before-first-open"/>
            <!-- Le nom de l'élément -->
            <xsl:variable name="TRAD" select="translate($after-first-open,'&gt;',' ')"/>
            <!--  TODO : Gere le cas <ELEMENT />   -->
            <xsl:variable name="ELEMENT" select="substring-before($TRAD,' ')"/>
            <xsl:variable name="suite" select="substring-after($after-first-open,$ELEMENT)"/>
            <xsl:variable name="DEFINITION" select="substring-before($suite,'&gt;')"/>
            <xsl:variable name="CONTENT" select="substring-after(substring-before($suite,concat('&lt;/',$ELEMENT)),concat($DEFINITION,'&gt;'))"/>
            <xsl:variable name="FOLLOWING">
                <xsl:choose>
                    <xsl:when test="substring($DEFINITION,string-length($DEFINITION))='/'"><!--  ends-with($DEFINITION,'/') not compatible with all XSLT version -->
                        <xsl:value-of select="substring-after($suite,'/&gt;')"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="substring-after(substring-after($suite,concat('&lt;/',$ELEMENT)),'&gt;')"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:element name="{$ELEMENT}">
                <xsl:call-template name="t-attribs">
                    <xsl:with-param name="TEXT" select="$DEFINITION"/>
                </xsl:call-template>
                <xsl:call-template name="t-convert">
                    <xsl:with-param name="TEXT" select="$CONTENT"/>
                </xsl:call-template>
            </xsl:element>
            <xsl:call-template name="t-convert">
                <xsl:with-param name="TEXT" select="$FOLLOWING"/>
            </xsl:call-template>
        </xsl:when>
        <!-- no more element -->
        <xsl:otherwise>
            <xsl:value-of select="$TEXT"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="t-attribs">
    <xsl:param name="TEXT"/>
    <xsl:if test="contains($TEXT,'=')">
        <!-- Assert TEXT=' NAME="VALUE".*' -->
        <xsl:variable name="NAME" select="substring-after(substring-before($TEXT,'='),' ')"/>
        <xsl:variable name="afterName" select="substring-after($TEXT,'=&quot;')"/>
        <xsl:variable name="VALUE" select="substring-before($afterName,'&quot;')"/>
        <xsl:variable name="FOLLOWING" select="substring-after($afterName,'&quot;')"/>
        <xsl:attribute name="{$NAME}">
            <xsl:value-of select="$VALUE"/>
        </xsl:attribute>
        <xsl:call-template name="t-attribs">
            <xsl:with-param name="TEXT" select="FOLLOWING"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
<xsl:call-template name="t-convert">
        <xsl:with-param name="TEXT" select="//content"/>
</xsl:call-template>