当前位置: 首页 > 知识库问答 >
问题:

XSLT-转换XML文件

樊博雅
2023-03-14

我想将xml文件格式转换为另一种格式;使用XSL1.0或2.0版。

<ROOT_XML>
  <Struct id="_6" name="Result" context="_1" members="_9 _10 _11 _13 _14 "/>
  <FundamentalType id="_7" name="int" size="32" align="32"/>
  <FundamentalType id="_8" name="float" size="32" align="32"/>
  <Field id="_9" name="angle" type="_8" offset="0" context="_6"/>
  <Field id="_10" name="row" type="_7" offset="32" context="_6"/>
  <Field id="_11" name="cloth" type="_18" offset="96" context="_6"/>
  <Destructor id="_13" name="EmptyClass" artificial="1" throw="" context="_6">
  </Destructor>
  <Constructor id="_14" name="Result" context="_6">
    <Argument type="_20" location="f0:2" file="f0" line="2"/>
  </Constructor>
  <Constructor id="_15" name="Result" context="_6"/>
  <FundamentalType id="_17" name="unsigned int" size="32" align="32"/>
  <ArrayType id="_18" min="0" max="29u" type="_21" size="240" align="8"/>
  <ReferenceType id="_19" type="_6" size="32" align="32"/>
  <ReferenceType id="_20" type="_6c" size="32" align="32"/>
  <FundamentalType id="_21" name="char" size="8" align="8"/>
</ROOT_XML>
<Struct Result>
  <Fields>
    <Field name="angle"  type="float" size="32"/>
    <Field name="row"    type="int"   size="32"/>
    <Field name="cloth"  type="char"  size="240"/>
  </Fields> 
</Struct>

http://www.w3.org/1999/xsl/transform“version=”1.0“>

<xsl:template match="/ROOT_XML/Struct"> 

  <Struct><xsl:value-of select="name"/>
      <xsl:choose> 
         <xsl:when test="boolean(./@members)"> 
            <xsl:call-template name="tokenizeString"> 
                <xsl:with-param name="list" select="./@members"/> 
                <xsl:with-param name="delimiter" select="' '"/> 
            </xsl:call-template> 
        </xsl:when> 

        <xsl:otherwise/> 
     </xsl:choose>
   </Struct>

</xsl:template>


<!--############################################################--> 
<!--## Template to tokenize strings                           ##--> 
<!--############################################################--> 

<xsl:template name="tokenizeString"> 
    <!--passed template parameter --> 
    <xsl:param name="list"/> 
    <xsl:param name="delimiter"/> 

    <xsl:choose> 
      <xsl:when test="contains($list, $delimiter)">                 
            <member> 
                <!-- get everything in front of the first delimiter --> 
                <xsl:value-of select="substring-before($list,$delimiter)"/>
            </member> 

            <xsl:call-template name="tokenizeString"> 
                <!-- store anything left in another variable --> 
                <xsl:with-param name="list" select="substring-after($list,$delimiter)"/> 
                <xsl:with-param name="delimiter" select="$delimiter"/> 
            </xsl:call-template> 
        </xsl:when> 

        <xsl:otherwise> 
            <xsl:choose> 
                <xsl:when test="$list = ''"> 
                    <xsl:text/> 
                </xsl:when> 
               <xsl:otherwise> 
                    <member> 
                        <xsl:value-of select="$list"/> 
                    </member> 
                </xsl:otherwise> 
            </xsl:choose> 
        </xsl:otherwise> 

    </xsl:choose> 
</xsl:template>    

这段代码是从“struct”节点的“members”属性中提取相关ID的起点,以后只用于发出“field”节点。

<Struct Result>
  <Fields>
    <Field name="angle"  type="float" size="32"/>
    <Field name="row"    type="int"   size="32"/>
    <Field name="cloth"  type="char"  size="240"/>
  </Fields> 
</Struct>
<Struct Answer>
  <Fields>
    <Field name="direction" type="float" size="32"/>
    <Field name="col" type="int" size="32"/>
    <Field name="paper" type="char"  size="232"/>
  </Fields> 
</Struct>

xslt处理器需要解析Struct节点的'members'属性。“members”属性是字段ID的列表。

在上面的示例中:

只有“members=_9_10_11”是字段节点!因此应该像Michael以前那样输出它们。列表中的其余项被省略(即members=“_13_14”)

  <Struct><xsl:value-of select="name"/>
      <xsl:choose> 
         <xsl:when test="boolean(./@members)"> 
            <xsl:call-template name="tokenizeString"> 
                <xsl:with-param name="list" select="./@members"/> 
                <xsl:with-param name="delimiter" select="' '"/> 
            </xsl:call-template> 
        </xsl:when> 

        <xsl:otherwise/> 
     </xsl:choose>
   </Struct>

</xsl:template>


<!--############################################################--> 
<!--## Template to tokenize strings                           ##--> 
<!--############################################################--> 

<xsl:template name="tokenizeString"> 
    <!--passed template parameter --> 
    <xsl:param name="list"/> 
    <xsl:param name="delimiter"/> 

    <xsl:choose> 
      <xsl:when test="contains($list, $delimiter)">                 
            <member> 
                <!-- get everything in front of the first delimiter --> 
                <xsl:value-of select="substring-before($list,$delimiter)"/>

                <!-- TODO: select holds the member's id...
                    Q: how should we continue from here?? --> 
            </member> 

            <xsl:call-template name="tokenizeString"> 
                <!-- store anything left in another variable --> 
                <xsl:with-param name="list" select="substring-after($list,$delimiter)"/> 
                <xsl:with-param name="delimiter" select="$delimiter"/> 
            </xsl:call-template> 
        </xsl:when> 

        <xsl:otherwise> 
            <xsl:choose> 
                <xsl:when test="$list = ''"> 
                    <xsl:text/> 
                </xsl:when> 
               <xsl:otherwise> 
                    <member> 
                        <xsl:value-of select="$list"/> 

                        <!-- TODO: select holds the member's id...
                            Q: how should we continue from here?? --> 

                    </member> 
                </xsl:otherwise> 
            </xsl:choose> 
        </xsl:otherwise> 

    </xsl:choose> 
</xsl:template>   

<xsl:template match="Field[key('f-type', @type)]">
    <xsl:variable name="f-type" select="key('f-type', @type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$f-type/@size}"/>
</xsl:template>

<xsl:template match="Field[key('a-type', @type)]">
    <xsl:variable name="a-type" select="key('a-type', @type)" />
    <xsl:variable name="f-type" select="key('f-type', $a-type/@type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$a-type/@size}"/>
</xsl:template>

共有1个答案

茅秦斩
2023-03-14

以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="f-type" match="FundamentalType" use="@id" />
<xsl:key name="a-type" match="ArrayType" use="@id" />

<xsl:template match="ROOT_XML">
    <Struct>
        <xsl:apply-templates select="Field"/>
    </Struct>
</xsl:template> 

<xsl:template match="Field[key('f-type', @type)]">
    <xsl:variable name="f-type" select="key('f-type', @type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$f-type/@size}"/>   
</xsl:template>

<xsl:template match="Field[key('a-type', @type)]">
    <xsl:variable name="a-type" select="key('a-type', @type)" />
    <xsl:variable name="f-type" select="key('f-type', $a-type/@type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$a-type/@size}"/>   
</xsl:template>

</xsl:stylesheet>

应用于示例输入时,将返回:

<?xml version="1.0" encoding="UTF-8"?>
<Struct>
  <Field name="angle" type="float" size="32"/>
  <Field name="row" type="int" size="32"/>
  <Field name="cloth" type="char" size="240"/>
</Struct>

工作原理:

  • 如果字段类型基本类型ID匹配,则从匹配的基本类型中查找类型大小值;
  • 如果字段类型ArrayTypeID匹配,则从匹配的ArrayType查找大小值,而从基本类型查找类型值,该基本类型的IDArrayType属性匹配。

如果您希望每个结构只包含字段,其ID列在其成员属性中,您可以这样做:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="field" match="Field" use="@id" />
<xsl:key name="f-type" match="FundamentalType" use="@id" />
<xsl:key name="a-type" match="ArrayType" use="@id" />

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

<xsl:template match="/ROOT_XML">
    <root>
        <xsl:for-each select="Struct">
            <Struct name="{@name}">
                <xsl:apply-templates select="key('field', tokenize(@members, ' '))"/>
            </Struct>
        </xsl:for-each> 
    </root>
</xsl:template> 

<xsl:template match="Field[key('f-type', @type)]">
    <xsl:variable name="f-type" select="key('f-type', @type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$f-type/@size}"/>   
</xsl:template>

<xsl:template match="Field[key('a-type', @type)]">
    <xsl:variable name="a-type" select="key('a-type', @type)" />
    <xsl:variable name="f-type" select="key('f-type', $a-type/@type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$a-type/@size}"/>   
</xsl:template>

</xsl:stylesheet>

XSLT1.0中也是这样:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="field" match="Field" use="@id" />
<xsl:key name="f-type" match="FundamentalType" use="@id" />
<xsl:key name="a-type" match="ArrayType" use="@id" />

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

<xsl:template match="/ROOT_XML">
    <root>
        <xsl:for-each select="Struct">
            <xsl:variable name="members">
                <xsl:call-template name="tokenize">
                    <xsl:with-param name="text" select="@members"/>
                </xsl:call-template>
            </xsl:variable>
            <Struct name="{@name}">
                <xsl:apply-templates select="key('field', exsl:node-set($members)/token)"/>
            </Struct>
        </xsl:for-each> 
    </root>
</xsl:template> 

<xsl:template match="Field[key('f-type', @type)]">
    <xsl:variable name="f-type" select="key('f-type', @type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$f-type/@size}"/>   
</xsl:template>

<xsl:template match="Field[key('a-type', @type)]">
    <xsl:variable name="a-type" select="key('a-type', @type)" />
    <xsl:variable name="f-type" select="key('f-type', $a-type/@type)" />
    <Field name="{@name}" type="{$f-type/@name}" size="{$a-type/@size}"/>   
</xsl:template>

<xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="' '"/>
    <xsl:choose>
        <xsl:when test="contains($text, $delimiter)">
            <token>
                <xsl:value-of select="substring-before($text, $delimiter)"/>
            </token>
            <!-- recursive call -->
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <token>
                <xsl:value-of select="$text"/>
            </token>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>


</xsl:stylesheet>
 类似资料:
  • XML输入文件: XML输入文件转换为XML输出文件。将XML输入文件的firstName、middleName和lastName标签合并为XML Ouput文件的name标签,将XML输入文件的address1、address2、city、state和pincode标签合并为XML Ouput文件的address标签。 我几乎转换了代码,但我在这里与empId作斗争。我已经在XSLT文件中手动输

  • 问题内容: 我想使用xsl文件转换一些xml并以某种方式输出结果(我使用的是Android Api Level 8)。 我当前的活动看起来像这样,但是转换器保持为空。LogCat引发一个with ,表示xml格式不正确,但是我确定它是正确的。 我在LogCat中发现了一条提示,提示在上述错误消息之前。 我究竟做错了什么? 这是要转换的xml文件(source.xml) 这是对应的xsl(produ

  • 我想使用XSLT将一些XML转换为JSON。XML如下所示: 我希望JSON如下所示: 推荐的方法是什么? 我已经有了一个方法,它看起来不太好,因为它只适用于xslt 1.0(我认为)和文本块。请参阅此处:https://xsltfiddle.liberty-development.net/naZYrpy/1 我更喜欢使用xslt 3.0和xml to json函数的更有效方法,但似乎不可能添加额

  • 您能帮助如何用子节点分割成半节点吗? 输入: 输出: 不幸的是,我对xslt没有经验,也没有找到这样的例子。 更新后,我尝试了下面建议的方法之一,并有这个https://xsltfiddle.liberty-development.net/jyH9rNq/3节点不复制 xslt: 输出:

  • 我有以下问题。我不是XSLT方面最伟大的专家,我想成功的是将一个XML从赛贝斯转换为以下内容: Sybase的输出: 我希望它的输出标题保持原样,条目部分不同 这是到目前为止我的XSLT(对不起,不太可能) 也许,有人可以帮我实现我想要的。非常感谢你。

  • 本文向大家介绍ASP.NET使用xslt将xml转换成Excel,包括了ASP.NET使用xslt将xml转换成Excel的使用技巧和注意事项,需要的朋友参考一下 序:   最近在给客户做一个管理系统的时候,客户提出要将查询结果导出到Excel。对于还是实习生的我倍感压力,于是找了点资料。网上有个示例,其中方法十分简单。于是照猫画虎,把方法和心得与大家分享。OK,Let`s go 第一步:   创