简体   繁体   中英

Modify XML to Order Mid-level Complextype Elements by Name

Edit: See This link for follow-up question

I have a large FOR XML EXPLICIT query in SQL Server 2008 R2 that creates an xml file, but it is failing to validate against my XSD schema because some of the mid-level elements appear in the wrong order. Here is an example XML file to show what I mean:

<Things>
  <Thing>
    <Racecars>
      <Racecar>
        <Colour>Red</Colour>
        <Rockets>Y</Rockets>
      </Racecar>
      <Racecar>
        <Colour>Blue</Colour>
        <Rockets>N</Rockets>
      </Racecar>
    </Racecars>
  </Thing>
  <Thing>
    <Numbers>
      <Number>
        <NumericName>1</NumericName>
        <WrittenName>One</WrittenName>
      </Number>
      <Number>
        <NumericName>2</NumericName>
        <WrittenName>Two</WrittenName>
      </Number>
    </Numbers>
  </Thing>
  <Thing>
    <Letters>
      <Letter>
        <AlphaName>A</AlphaName>
        <PhoneticName>Ay</PhoneticName>
      </Letter>
      <Letter>
        <AlphaName>B</AlphaName>
        <PhoneticName>Bee</PhoneticName>
      </Letter>
    </Letters>
  </Thing>
</Things>

The way that the XML EXPLICIT command works means that each group containing some attributes are in order (the bottom level in this case), but I do not know how to control the order of the attributes directly below the (in this case) "Thing" Level. How can I specify that the child elements of "Thing" should appear in alphabetical order by name when there is no attribute data for SQL to ORDER BY?

As I mentioned, this is a big bit of XML, with many different elements, which do not always all appear, so if there were some way to order all of the child elements at a certain level, without affecting the ordering of the grandchild elements without having to hard-code each element name, that would be really great.

I have searched all over the place to no avail for a method. I have looked at both an ex post facto xquery modify on my XML output (which seems to me the most practical solution as some of the elements to be sorted have minOccurs = 0), or as part of the design of the FOR XML EXPLICIT command (which seems the most efficient as that way prevents rather than undoes the error) but, of what I have understood, nothing seems to work.

I could, of course, remove the constraints from the schema file, but would much rather avoid this if at all possible as giving in to inexactitude seems the wrong direction to step.

With the above file, this is the outcome I would consider ideal:

<Things>
  <Thing>
    <Letters>
      <Letter>
        <AlphaName>A</AlphaName>
        <PhoneticName>Ay</PhoneticName>
      </Letter>
      <Letter>
        <AlphaName>B</AlphaName>
        <PhoneticName>Bee</PhoneticName>
      </Letter>
    </Letters>
  </Thing>
  <Thing>
    <Numbers>
      <Number>
        <NumericName>1</NumericName>
        <WrittenName>One</WrittenName>
      </Number>
      <Number>
        <NumericName>2</NumericName>
        <WrittenName>Two</WrittenName>
      </Number>
    </Numbers>
  </Thing>
  <Thing>
    <Racecars>
      <Racecar>
        <Colour>Red</Colour>
        <Rockets>Y</Rockets>
      </Racecar>
      <Racecar>
        <Colour>Blue</Colour>
        <Rockets>N</Rockets>
      </Racecar>
    </Racecars>
  </Thing>
</Things>

As you can see, the three elements below "Thing" are now sorted alphabetically (Letters,Numbers,Racecars) but all elements within each of these are unchanged in order.

Please let me know if you would like me to write out a SELECT ... FOR XML EXPLICIT to generate the example XML above; I will gladly do so - I just expected that the answer would be in the form of an xquery directly on the XML above, so thought it unlikely to be needed!

You have to reconstruct the <Things/> elements, ordering by the <Thing/> 's name. This snippet orders by the first child's name, as we need a single value to sort after. Regarding the input given, it does not seem necessary to order inside the <Thing/> (and might even be wrong).

element Things {
  for $thing in /Things/Thing
  let $name := local-name(($thing/*)[1])
  order by $name
  return $thing
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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