代码之家  ›  专栏  ›  技术社区  ›  Scanningcrew

将XML转换为指定的顺序(DTD->XSD)

  •  1
  • Scanningcrew  · 技术社区  · 15 年前

    我有一个项目,其中我们正在处理的主文件是一个旧的XML文件,其中创建者创建了一个非常非结构化的DTD(所有元素都是可选的,可以出现0次或更多次)。更妙的是,读取文件的应用程序实际上需要许多值(如需要)。我根据已知的应用程序需求创建了一个XSD,并将无序元素列表移动到XSD中的序列中。

    是否有一个简单的转换过程(例如XSLT)可以接受旧的XML文件,并以指定的方式对其元素进行排序,以便我们可以使用新的XSD对其进行验证?

    <Top>
      <A/>
      <D/>
      <B/>
      <C/>
      <A/>
    </TOP>
    

    进入

    <Top>
      <A/>
      <A/>
      <B/>
      <C/>
      <D/>
    </TOP>
    

    2 回复  |  直到 15 年前
        1
  •  6
  •   Erlock    15 年前

    您可以以更具声明性的方式使用样式表中嵌入的“查找列表”,而不是指定要在模板中排序的所有元素:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:my="my-namespace" 
       exclude-result-prefixes="my">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      <my:Top>
        <my:A>
          <my:AA/>
          <my:AB/>
          <my:AC/>
        </my:A>
        <my:B/>
        <my:C/>
        <my:D/>
      </my:Top>
      <xsl:template match="my:*">
        <xsl:param name="source"/>
        <xsl:variable name="current-lookup-elem" select="current()"/>
        <xsl:for-each select="$source/*[name()=local-name($current-lookup-elem)]">
          <xsl:copy>
            <xsl:apply-templates select="$current-lookup-elem/*">
              <xsl:with-param name="source" select="current()"/>
            </xsl:apply-templates>
            <xsl:copy-of select="text()"/>
          </xsl:copy>
        </xsl:for-each>
      </xsl:template>
      <xsl:template match="/Top">
        <xsl:apply-templates select="document('')/*/my:*">
          <xsl:with-param name="source" select="/"/>
        </xsl:apply-templates>
      </xsl:template>
    </xsl:stylesheet>
    

    <Top>
      <A>
        <AC/>
        <AA/>
      </A>
      <D/>
      <B/>
      <C>yyy</C>
      <A>
        <AB/>
        <AC/>
        <AA>xxx</AA>
      </A>
    </Top>
    

    将返回:

    <Top>
        <A>
            <AA>xxx</AA>
            <AC/>
        </A>
        <A>
            <AA/>
            <AB/>
            <AC/>
        </A>
        <B/>
        <C>yyy</C>
        <D/>
    </Top>
    
        2
  •  1
  •   carillonator    15 年前

    我假设您不想按字母顺序排列元素,而是按指定的顺序排列。试试这个——您将需要一个XSLT处理器(例如。 Saxon

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" version="1.0" />
    
    <xsl:template match="Top">
       <xsl:copy>
          <xsl:for-each select="A">
             <xsl:copy-of select="." />  
          </xsl:for-each> 
          <xsl:for-each select="B">
             <xsl:copy-of select="." />  
          </xsl:for-each>  
          <xsl:for-each select="C">
             <xsl:copy-of select="." />  
          </xsl:for-each>  
          <xsl:for-each select="D">
             <xsl:copy-of select="." />  
          </xsl:for-each>
       </xsl:copy>  
    </xsl:template>
    
    </xsl:stylesheet>
    

    但要注意:XML是区分大小写的,所以 <Top> </TOP> 标记不匹配,因此您没有格式良好的XML,因此XSLT处理器将抛出错误并退出。

    <xsl:copy-of> xsl:copy-of xsl:copy