【问题标题】:Using XSLT to sort elements that will match the correct schema XSD使用 XSLT 对将匹配正确模式 XSD 的元素进行排序
【发布时间】:2011-12-27 22:32:25
【问题描述】:

我想做这样的事情Can you transform unordered xml to match an xsd:sequence order? bu 比这更复杂一点。例如:

<person> 
   <addressList>
        <address>
            <city>Chicago</city>
            <state>IL</state>
            <zip>41111</zip>
        </address>
        <address>
            <state>MO</state>
            <zip>64521</zip>
            <city>Kansas City</city>
        </address>
   </addressList>  
   <lastname>The BFG</lastname> 
   <firstname>1234567890</firstname>
</person>

我无法控制架构,因此这与架构匹配,但是当我尝试反序列化时抛出错误......所以解决方案是使用 XSLT 将其转换为匹配 XSD 格式。我只想获得相同的输入,但顺序不同,例如:

请注意,第二个地址、名字和姓氏中的城市是移动的。

<person>  
   <lastname>The BFG</lastname> 
   <firstname>1234567890</firstname>
   <addressList>
        <address>
            <city>Chicago</city>
            <state>IL</state>
            <zip>41111</zip>
        </address>
        <address>
            <city>Kansas City</city>
            <state>MO</state>
            <zip>64521</zip>
        </address>
   </addressList> 
</person>

【问题讨论】:

标签: c# .net xslt xsd schema


【解决方案1】:

这种转变

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

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

 <xsl:template match="/*">
  <xsl:copy>
   <xsl:apply-templates select="firstname|lastname"/>

   <xsl:apply-templates select="addressList"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="address">
  <xsl:copy>
   <xsl:apply-templates select="city"/>
   <xsl:apply-templates select="state"/>
   <xsl:apply-templates select="zip"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时

<person>
    <addressList>
        <address>
            <city>Chicago</city>
            <state>IL</state>
            <zip>41111</zip>
        </address>
        <address>
            <state>MO</state>
            <zip>64521</zip>
            <city>Kansas City</city>
        </address>
    </addressList>
    <lastname>The BFG</lastname>
    <firstname>1234567890</firstname>
</person>

产生想要的正确结果

<person>
   <lastname>The BFG</lastname>
   <firstname>1234567890</firstname>
   <addressList>
      <address>
         <city>Chicago</city>
         <state>IL</state>
         <zip>41111</zip>
      </address>
      <address>
         <city>Kansas City</city>
         <state>MO</state>
         <zip>64521</zip>
      </address>
   </addressList>
</person>

解释

  1. 身份规则(未覆盖时)“按原样”匹配每个节点。

  2. 我们只覆盖元素的标识模板,其子元素的顺序需要在输出中更改/

  3. 要以不同于文档顺序的顺序处理和输出节点,需要指定一系列 xsl:apply-templates 指令,明确指定所需的新处理顺序。

【讨论】:

    【解决方案2】:

    基于之前的链接 (Transform XML into specified ordering (DTD -> XSD)),我们需要做的唯一更改是 XSLT 文档内部的 xml 和根名称(Top 代表 person)和新的 XSLT 看起来像:

    <?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:person>  
           <my:lastname/> 
           <my:firstname/>
           <my:addressList>
                <my:address>
                    <my:city/>
                    <my:state/>
                    <my:zip/>
                </my:address>
           </my:addressList> 
        </my:person>
      <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="/person">
        <xsl:apply-templates select="document('')/*/my:*">
          <xsl:with-param name="source" select="/"/>
        </xsl:apply-templates>
      </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

      猜你喜欢
      • 2019-05-08
      • 2020-11-12
      • 2021-08-12
      • 2021-08-13
      • 1970-01-01
      • 2010-10-09
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      相关资源
      最近更新 更多