views:

329

answers:

1

Here's a link to my previous question on this same block of code with a working shred example

Ok, I'm a C# ASP.NET dev following orders: The orders are to take a given dataset, shred the XML and return columns. I've argued that it's easier to do the shredding on the ASP.NET side where we already have access to things like deserializers, etc, and the entire complex of known types, but no, the boss says "shred it on the server, return a dataset, bind the dataset to the columns of the gridview" so for now, I'm doing what I was told. This is all to head off the folks who will come along and say "bad requirements".

Task at hand:

Current code that doesn't work:

And if we modify the previous post to include namespaces on the XML elements, we lose the functionality that the previous post has...

DECLARE @table1 AS TABLE (
    ProductID    VARCHAR(10)
  , Name         VARCHAR(20)
  , Color        VARCHAR(20)
  , UserEntered  VARCHAR(20)
  , XmlField     XML
)

INSERT INTO @table1 SELECT '12345','ball','red','john','<sizes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;size xmlns="http://example.com/ns" name="medium"><price>10</price></size><size xmlns="http://example.com/ns" name="large"><price>20</price></size></sizes>'
INSERT INTO @table1 SELECT '12346','ball','blue','adam','<sizes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;size xmlns="http://example.com/ns" name="medium"><price>12</price></size><size xmlns="http://example.com/ns" name="large"><price>25</price></size></sizes>'
INSERT INTO @table1 SELECT '12347','ring','red','john','<sizes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;size xmlns="http://example.com/ns" name="medium"><price>5</price></size><size xmlns="http://example.com/ns" name="large"><price>8</price></size></sizes>'
INSERT INTO @table1 SELECT '12348','ring','blue','adam','<sizes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;size xmlns="http://example.com/ns" name="medium"><price>8</price></size><size xmlns="http://example.com/ns" name="large"><price>10</price></size></sizes>'
INSERT INTO @table1 SELECT '23456','auto','black','ann','<auto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;type xmlns="http://example.com/ns"&gt;car&lt;/type&gt;&lt;wheels xmlns="http://example.com/ns"&gt;4&lt;/wheels&gt;&lt;doors xmlns="http://example.com/ns"&gt;4&lt;/doors&gt;&lt;cylinders xmlns="http://example.com/ns"&gt;3&lt;/cylinders&gt;&lt;/auto&gt;'
INSERT INTO @table1 SELECT '23457','auto','black','ann','<auto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;type xmlns="http://example.com/ns"&gt;truck&lt;/type&gt;&lt;wheels xmlns="http://example.com/ns"&gt;4&lt;/wheels&gt;&lt;doors xmlns="http://example.com/ns"&gt;2&lt;/doors&gt;&lt;cylinders xmlns="http://example.com/ns"&gt;8&lt;/cylinders&gt;&lt;/auto&gt;&lt;auto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;&lt;type xmlns="http://example.com/ns"&gt;car&lt;/type&gt;&lt;wheels xmlns="http://example.com/ns"&gt;4&lt;/wheels&gt;&lt;doors xmlns="http://example.com/ns"&gt;4&lt;/doors&gt;&lt;cylinders xmlns="http://example.com/ns"&gt;6&lt;/cylinders&gt;&lt;/auto&gt;'

DECLARE @x XML
-- I think I'm supposed to use WITH XMLNAMESPACES(...) here but I don't know how
SELECT @x = (
    SELECT 
        ProductID
      , Name
      , Color
      , UserEntered
      , XmlField.query('
            for $vehicle in //auto
            return <auto 
                type = "{$vehicle/type}"
                wheels = "{$vehicle/wheels}"
                doors = "{$vehicle/doors}"
                cylinders = "{$vehicle/cylinders}"
            />')
    FROM @table1 table1
    WHERE Name = 'auto'
    FOR XML AUTO
)

SELECT @x

SELECT 
    ProductID    = T.Item.value('../@ProductID', 'varchar(10)')
  , Name         = T.Item.value('../@Name', 'varchar(20)')
  , Color        = T.Item.value('../@Color', 'varchar(20)')
  , UserEntered  = T.Item.value('../@UserEntered', 'varchar(20)')
  , VType        = T.Item.value('@type' , 'varchar(10)')
  , Wheels       = T.Item.value('@wheels', 'varchar(2)')
  , Doors        = T.Item.value('@doors', 'varchar(2)')
  , Cylinders    = T.Item.value('@cylinders', 'varchar(2)')
FROM   @x.nodes('//table1/auto') AS T(Item)

If my previous post shows there's a much better way to do this, then I really need to revise this question as well, but on the off chance this coding-style is good, I can probably go ahead with this as-is...

Any takers?

+2  A: 
DECLARE @x XML;
with xmlnamespaces ('http://www.w3.org/2001/XMLSchema-instance' as xsi
    , 'http://www.w3.org/2001/XMLSchema' as xsd
    , 'http://example.com/ns' as ns) 
SELECT @x = (
    SELECT 
        ProductID
      , Name
      , Color
      , UserEntered
      , XmlField.query('
            for $vehicle in //auto
            return <auto 
                type = "{$vehicle/ns:type}"
                wheels = "{$vehicle/ns:wheels}"
                doors = "{$vehicle/ns:doors}"
                cylinders = "{$vehicle/ns:cylinders}"
            />')
    FROM @table1 table1
    WHERE Name = 'auto'
    FOR XML AUTO
)
Remus Rusanu
@Remus Rusanu ~ As before, many thanks for the rapid answer. I didn't realize that was all it would take on the namespaces, I figured it was going to be much more complex than that. Ah well, at least I knew what to ask for :\ ...
drachenstern
Namespaces are a tricky beast. You seem to be in fairly good control of this problem (the whole XML shredding issue) and I have no doubt you'll land on your feet.
Remus Rusanu
@Remus Rusanu ~ Again, many thanks!
drachenstern