繁体   English   中英

如何转换xml中的无序元素以匹配xsd:sequence顺序?

[英]How to transform unordered elements in xml to match an xsd:sequence order?

同等命名子元素的答案相比,我尝试转换以下内容:

<Person>
    <Address>5</Address>
    <Firstname>1234567890</Firstname>
    <Lastname>
        <MaidenName>The BFG</MaidenName>
        <StageName>GFB eht</StageName>
    </Lastname>
</Person>

进入所需结果:

<Person>    
    <Firstname>1234567890</Firstname>
    <Lastname>
        <StageName>GFB eht</StageName>
        <MaidenName>The BFG</MaidenName>    
    </Lastname>
    <Address>5</Address>    
</Person>

但是继续出现以下错误:
xml2xml.xsl的第47行的xsl:element错误:XTDE0820:提供的元素名称是零长度的字符串

元素如何以正确的顺序传递和插入?

所需结果符合所提供的XML模式:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="Person" type="Person"/>
   <xs:complexType name="Person">
      <xs:sequence>
        <xs:element name="Firstname" type="xs:string"/>
        <xs:element name="Lastname" type="Lastname"/>
        <xs:element name="Address" type="xs:string"/>
      </xs:sequence>
   </xs:complexType>
  <xs:complexType name="Lastname">
    <xs:sequence>
        <xs:element name="StageName" type="xs:string"/>
        <xs:element name="MaidenName" type="xs:string"/>
    </xs:sequence>
   </xs:complexType>
</xs:schema>

我正在使用这种转换,它是从获得的, 您可以转换无序xml以匹配xsd:sequence顺序吗? xsdsequence-order并尝试适应:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kxsElemByName" match="xs:complexType" use="@name"/>

 <xsl:variable name="vSchema" select=
 "document('file:///D:/xslt/test/schema.xsd')"/> 

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

 <xsl:template match="/*">
  <xsl:variable name="vElem" select="."/>

  <xsl:for-each select="$vSchema">
   <xsl:apply-templates select=
     "key('kxsElemByName', name($vElem))">
    <xsl:with-param name="pElement" select="$vElem"/>
   </xsl:apply-templates>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="xs:complexType">
  <xsl:param name="pElement"/>

  <xsl:element name="{name($pElement)}">
       <xsl:apply-templates mode="generate"
            select="xs:sequence/*">
         <xsl:with-param name="pParent" select="$pElement"/>
       </xsl:apply-templates>
  </xsl:element>
 </xsl:template>

 <xsl:template match="xs:element" mode="generate">
      <xsl:param name="pParent"/>

      <xsl:variable name="vProp" select=
      "$pParent/*[local-name(.) = local-name(current())]/*"/>
      <xsl:element name="{local-name($vProp)}">
       <xsl:value-of select="$vProp"/>
   </xsl:element>
 </xsl:template>

</xsl:stylesheet>

我认为这从根本上是错误的。 您想要一种适用于任何模式的通用解决方案,或者想要一种针对某个特定模式的解决方案。 目前,您正在尝试从架构中提取结构,但是您已经对架构的编写方式做出了许多假设,以至于解决方案非常脆弱(我什至不会尝试找到该架构)。特定错误)。 例如,您假设:

  • 复杂类型的名称与元素的名称匹配
  • 模式不使用包含或导入
  • 复杂类型包含xs:sequence,而xs:sequence仅包含元素粒子
  • 序列中的所有元素仅发生一次
  • 元素粒子是局部元素声明,而不是对全局元素声明的引用

这些假设是如此严格,以至于您真的可以将规则硬编码为XSLT代码,而不是尝试从架构中提取它们。

如果要正确执行此操作,请不要尝试从源模式文档中进行工作,而应从模式编译器的输出中进行工作-例如,Saxon模式处理器生成的SCM文件或可以访问的模式信息。在XSLT中使用saxon:schema()扩展功能。

我不确定这是否真的是您所期望的,但是无论如何-通过这种方式可以创建所需的输出结构:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:template match="Person">
    <xsl:element name="Person">
        <xsl:copy-of select="Firstname" />
        <xsl:copy-of select="Lastname" />
        <xsl:copy-of select="Address" />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

通过重构所需元素并复制所有子节点来实现排序。

假设您只是想根据XSD调整顺序,请尝试以下XSLT。 对于源XML中的每个元素,它都会检查以在XSD中查找xs:element ,对于该xs:element是否为复杂类型。 如果是这样,那么它将相应地对子元素进行排序。

根据迈克尔的说法,这仍然非常脆弱。 凯的答案,尽管它不再依赖于与元素名称匹配的复杂类型的名称。

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" indent="yes" />

    <xsl:key name="kxsElemByName" match="xs:element" use="@name"/>
    <xsl:key name="kxsTypeByName" match="xs:complexType" use="@name"/>

    <xsl:variable name="vSchema" select="document('file:///D:/xslt/test/schema.xsd')"/> 

    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*" priority="2">
        <xsl:variable name="current" select="." />
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each select="$vSchema">
                <xsl:variable name="element" select="key('kxsElemByName', name($current))" />
                <xsl:variable name="complex" select="key('kxsTypeByName', $element/@type)" />
                <xsl:choose>
                <xsl:when test="$complex">
                    <xsl:for-each select="$complex/xs:sequence/xs:element">
                        <xsl:apply-templates select="$current/*[name() = current()/@name]" />
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="$current/node()"/>
                </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM