Использование XSLT для сортировки элементов, которые будут соответствовать правильной схеме XSD - PullRequest
2 голосов
/ 26 декабря 2011

Я хочу сделать что-то вроде этого Можете ли вы преобразовать неупорядоченный xml, чтобы он соответствовал порядку xsd: sequence? но немного сложнее, чем это. Например:

<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>

Ответы [ 2 ]

2 голосов
/ 27 декабря 2011

На основании предыдущей ссылки ( Преобразование XML в указанный порядок (DTD -> XSD) ), единственные изменения, которые мы должны сделать, - это XML внутри документа XSLT и имя корня (Topдля человека) и новый 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>
2 голосов
/ 26 декабря 2011

Это преобразование :

<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 инструкций, которая явно указывает желаемый новый порядок обработки.

...