使用XSLT自动创建xml元素
我想根据输入文件表达式自动化元素 我的输入文件看起来像使用XSLT自动创建xml元素,xml,xslt,xpath,Xml,Xslt,Xpath,我想根据输入文件表达式自动化元素 我的输入文件看起来像 <?xml version="1.0" encoding="UTF-8"?> <mappings> <mapping inputContext="InputRoot" outputContext="outputRoot"> <input>InputParent/InputChild/InputSubChild</input> <outp
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping inputContext="InputRoot" outputContext="outputRoot">
<input>InputParent/InputChild/InputSubChild</input>
<output>OutputParent/OPChild</output>
</mapping>
</mappings>
InputParent/InputChild/InputSubChild
OutputParent/OPChild
基于上述XML,我创建了以下XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns="http://www.testmapping.org/mapping">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="outputCtxt" select="mappings/mapping/output"/>
<xsl:call-template name="contextGenerator">
<xsl:with-param name="contextPath" select="$outputCtxt"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="contextGenerator">
<xsl:param name="contextPath" as="xs:string?"/>
<xsl:variable name="currentContext" select="substring-before($contextPath,'/')"/>
<xsl:variable name="subContext" select="substring-after($contextPath,'/')"/>
<xsl:element name="{$currentContext}">
<xsl:call-template name="contextGenerator">
<xsl:with-param name="contextPath" select="$subContext"/>
</xsl:call-template>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
我期待以下格式的输出
<outputRoot>
<OutputParent>
<OPChild></OPChild>
</OutputParent>
</outputRoot>
当我尝试基于输入进行转换时,我最终会出现预期的QName错误。我可以提出一些建议来解决这个问题。在XML中,元素名称必须符合的词汇结构。您正在尝试创建一个名为
InputParent/InputChild/InputSubChild
的元素。这包含QName中不允许的字符(/
)
要修复错误,可以用/
替换.
。。。取决于您的需求
例如
上下文生成器模板未正确拆分和递归。(第二次调用时,
contextGenerator
的参数中没有/
,因此拆分失败。)
将以下内容添加到模板有助于显示问题:
<xsl:message>
[<xsl:value-of select="$currentContext"/>]
[<xsl:value-of select="$subContext"/>]
</xsl:message>
以下替换模板生成正确的输出:
<xsl:template name="contextGenerator">
<xsl:param name="contextPath" as="xs:string?"/>
<xsl:choose>
<xsl:when test="contains($contextPath, '/')">
<xsl:element name="{substring-before($contextPath, '/')}">
<xsl:variable name="subContext"
select="substring-after($contextPath, '/')"/>
<xsl:if test="$subContext">
<xsl:call-template name="contextGenerator">
<xsl:with-param name="contextPath" select="$subContext"/>
</xsl:call-template>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$contextPath}"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
结果:
<OutputParent>
<OPChild/>
</OutputParent>
使用XSLT 2.0可以提供更短、更简单和更高效的解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vOutNames" select=
"tokenize(/*/*/output, '/')"/>
<xsl:template match="/">
<xsl:sequence select="my:gen($vOutNames)"/>
</xsl:template>
<xsl:function name="my:gen" as="element()?">
<xsl:param name="pNames" as="xs:string*"/>
<xsl:if test="$pNames[1]">
<xsl:element name="{$pNames[1]}">
<xsl:sequence select="my:gen($pNames[position() >1])"/>
</xsl:element>
</xsl:if>
</xsl:function>
</xsl:stylesheet>
当此转换应用于提供的XML文档时:
<mappings>
<mapping inputContext="InputRoot" outputContext="outputRoot">
<input>InputParent/InputChild/InputSubChild</input>
<output>OutputParent/OPChild</output>
</mapping>
</mappings>
<OutputParent>
<OPChild/>
</OutputParent>
InputParent/InputChild/InputSubChild
OutputParent/OPChild
生成所需的正确结果:
<mappings>
<mapping inputContext="InputRoot" outputContext="outputRoot">
<input>InputParent/InputChild/InputSubChild</input>
<output>OutputParent/OPChild</output>
</mapping>
</mappings>
<OutputParent>
<OPChild/>
</OutputParent>
我在($contextPath,“/”)之前使用子字符串;这将在没有/部分结果的情况下提取第一个匹配项预期的输出不包含斜杠。@lwburk:完全正确。我读XSLT的速度太快了。我想知道为什么你还没有发布这个答案,因为在我到这里之前你已经研究这个问题一段时间了。现在我知道了+回答得好@你的递归模板没有终止条件,所以如果你没有得到一个错误,你会有一个无限的递归(实际上是堆栈溢出…)如果InputParent/InputChild/InputSubChild OutputParent/OPChild@LaxmikanthSamudrala:对不起,你想说什么?对不起,这是我在处理的其他XSLT问题上的错误;但我已经决定了。