Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用XSLT自动创建xml元素_Xml_Xslt_Xpath - Fatal编程技术网

使用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问题上的错误;但我已经决定了。