sql + xquery to delete multiple parent nodes - sql

In the below xml i have three 5 /Item elements, 4 of which have a Blob child element. I want to delete the elements that have a child Blob element but only where Item/#Name has the text "Blob" in it.
<Items>
<Item Name="Blob123">
<Blob/>
</Item>
<Item Name="Blob124">
<Blob/>
</Item>
<Item Name="Blob125">
<Blob/>
</Item>
<Item Name="Blob126">
</Item>
<Item Name="Xyz126">
<Blob/>
</Item>
</Items>
This query returns the 3 /Item elements named 'Blob%' and with a child /Blob element just fine.
select xmlVal.query('(/Items/Item[contains(#Name, "Blob")]/Blob/..)')
However when i attempt to delete those element using this xquery:
select xmlVal.modify('delete (/Items/Item[contains(#Name, "Blob")]/Blob/..)')
I get: Incorrect use of the XML data type method 'modify'. A non-mutator method is expected in this context.
What am i doing wrong.

In case it helps others, to fix this i need to use update/set and also needed to change the xpath slightly
update table1
set xmlVal.modify('delete (/Items/Item[contains(#Name, "Blob")][Blob])')

Related

Extracting singleton value from xml list

I am familiar with extracting values from xml using SQL in SQL Server, but now I need to identify the parent node with a particular "key node" value and get the value from its "value node."
<example>
<item>
<key>skip</key>
<value>True</value>
</item>
<item>
<key>test</key>
<value>True</value>
</item>
<item>
<key>number</key>
<value />
</item>
<item>
<key>country</key>
<value>USA</value>
</item>
<item>
<key>Account Number</key>
<value>1111111111</value>
</item>
<item>
<key>website</key>
<value>stackoverflow</value>
</item>
<item>
<key>type</key>
<value>Customer</value>
</item>
</example>
If I want to get the account number I could use this sql statement:
SELECT xml.value('(example/item/value)[5]','varchar(30)')
Since the item node is 5th down on the list, the singleton will be 5. But what if the position of the account number node can change? I want to be able to identify the account number based on the condition that key = 'Account Number.'
In other words, I want to SELECT value where key = 'Account Number'
The trick is to specify WHICH "item" you want in brackets, by specifying a key/value that is unique to the item. In this case, you want the one where the "key" node has the text "Account Number". You'd express it like this:
SELECT #xml.value('(example/item[key="Account Number"]/value)[1]','varchar(30)')

Retrieving All instances of an 3rd level XML field from an XML column

I have an XML data field in one of my tables that essentially looks like this:
<App xmlns='http://Namespace1'>
<Package xmlns='http://Namespace2'>
<Item>
<ItemDetails xmlns='http://Namespace3'>
<ItemName>ItemNameValue</ItemName>
</ItemDetails>
other_item_stuff
</Item>
<Item>
<ItemDetails>
<ItemName>ItemNameValue</ItemName>
</ItemDetails>
</Item>
...
</Package>
</App>
I need to get all of the ItemNameValues from the XML.
I have tried to adapt many examples found on the web to my purpose, but have failed miserably. The best I seem to be able to do is get one ItemName per Package.
I think that CROSS APPLY is where I need to go, but the syntax to retrieve all the itemdetail.itemname eludes me.
This is my latest failure (returns nothing):
WITH XMLNAMESPACES(
'http://Namespace1' AS xsd,
'http://www.w3.org/2001/XMLSchema-instance' AS xsi,
'http://Namespace2' AS ns1,
'http://Namespace3' AS ns2)
Items.d.value('(ns2:ItemDetails/ItemName/text())[1]','varchar(200)') as
ItemName
FROM MyTable
CROSS APPLY XMLDataColumn.nodes('/xsd:App/ns1:Package/ns1:Item') Items(d)
I hope to get several records from each XML field, but can only ever get the first element.
The biggest problem in this issue is the XML itself:
<App xmlns="http://Namespace1">
<Package xmlns="http://Namespace2">
<Item>
<ItemDetails xmlns="http://Namespace3">
<ItemName>ItemNameValue</ItemName>
</ItemDetails>
other_item_stuff
</Item>
<Item>
<ItemDetails>
<ItemName>ItemNameValue</ItemName>
</ItemDetails>
</Item>
...
</Package>
</App>
Two major Problems:
The namespaces are all declared as default namespaces (they do not include a prefix). All nodes within a node share the same default namespace, if there is nothing else stated explicitly.
The first <ItemDetails> is living within namespace http://Namespace3, while the second <ItemDetails> is living within namespace http://Namespace2 (inherited from <Package>)
That means: If you can - by any chance - change the construction of the XML, try to do this first.
If you have to deal with this, you can try this clean, but clumsy approach.
WITH XMLNAMESPACES(
'http://Namespace1' AS ns1,
'http://www.w3.org/2001/XMLSchema-instance' AS xsi,
'http://Namespace2' AS ns2,
'http://Namespace3' AS ns3)
SELECT COALESCE(Items.d.value('(ns2:ItemDetails/ns2:ItemName/text())[1]','varchar(200)')
,Items.d.value('(ns3:ItemDetails/ns3:ItemName/text())[1]','varchar(200)')) AS ItemName
FROM #xml.nodes('/ns1:App/ns2:Package/ns2:Item') Items(d);
Another approach is to use a namespace wildcard, but be aware of ambigous names...
SELECT Items.d.value('(*:ItemDetails/*:ItemName/text())[1]','varchar(200)') AS ItemName
FROM #xml.nodes('/*:App/*:Package/*:Item') Items(d)

Build New XML From Stored XML Value

We store rather large XML blobs (in an column of XML type) and I'm pursuing a skunkworks project to try to build up a subset of the XML on the fly when needed.
Let's say I have this XML blob stored in our database table in a given column:
<root>
<header>
<id>1</id>
<name id="foo">Name</name>
</header>
<body>
<items>
<addItem>
<val>1</val>
</addItem>
<observeItem>
<val>2</val>
</observeItem>
</items>
</body>
</root>
What I want to get out is this is to basically recreate the above document structure but only include one of the items children, so for example:
<root>
<header>
<id>1</id>
<name id="foo">Name</name>
</header>
<body>
<items>
<observeItem>
<val>2</val>
</observeItem>
</items>
</body>
</root>
If I were interested in just the observeItem record (the items element can have any number of children, but I'll only ever be interested in a single one of them).
I know I can do something like SELECT #XML.query('//items/child::*[2]') to get just a given child item, but how would I build up the full original document in a query with just one of those children?
I've come up with a solution, but I'm not entirely pleased with it:
DECLARE #XML XML = '
<root>
<header>
<id>1</id>
<name id="foo">Name</name>
</header>
<body>
<items>
<addItem>
<val>1</val>
</addItem>
<observeItem>
<val>2</val>
</observeItem>
</items>
</body>
</root>'
DECLARE #NthChild INT = 2
SELECT
#XML.query('//header'),
#XML.query('//items/child::*[sql:variable("#NthChild")]') AS 'items'
FOR XML PATH('root')
I don't like having to specify the root explicitly nor the items, but I think this approach could get me by.

Speech Recognition Grammar Specification: semantic results

I'm currently developing an application of Speech Recognition using Microsoft Kinect SDK. The goal of the application is to load any (valid) XML file containing the grammar and use it to process speech.
I'm in the process of testing the application by developing not so simple grammars and during that process I haven't figured out how to return specific semantic values, in particular names. For example, in the following grammar:
<grammar version="1.0" xml:lang="en-US" root="rootRule" tag-format="semantics/1.0-literals" xmlns="http://www.w3.org/2001/06/grammar">
<!-- Ask for person's related information (age, location, name, etc.) -->
<rule id="rootRule">
<one-of>
<!-- Ask person name -->
<item>
<tag>AnswerToNameQuestion</tag>
<one-of>
<item> my name is </item>
<item> people call me </item>
</one-of>
<ruleref uri="#names"/>
</item>
<!-- Ask person location -->
<item>
<tag>QuestionOfLocation</tag>
<one-of>
<item> do you know where is </item>
<item> can you tell me where </item>
<item> where did </item>
</one-of>
<ruleref uri="#names"/>
</item>
</one-of>
</rule>
<!-- Answer person name -->
<rule id="names">
<item>
<one-of>
<item> peter </item>
<item> john </item>
<item> danny </item>
</one-of>
</item>
</rule>
</grammar>
When a person says their name, I want the semantic to be the name of that person. For example, for the question "What is your name" (not included in this grammar), and a reply "My name is -insert name-", I wanted the semantic results to be the name of the person and not simply "AnswerToNameQuestion" semantic result that is being returned right now.
Any help would be greatly appreciated!
In the SpeechRecognized event handler. You can get the "textual sentence" if you query the event.Result.Text property instead of event.Result.Semantics.Value. You can use this second property to remove from text string the non-relevant portion.
For example, if somebody says "my name is Peter", inside SpeechRecognized event handler you will have:
event.Result.Text = "my name is Peter"
event.Result.Semantics.Value = "AnswerToNameQuestion"

TBXML not parsing TBXMLElement text, while child element tags also present in existing parent tag?

My XML is like this:
<office>
<item>
NOIDA OFFICE:
<OfficeAddress>B-20, SECTOR 57 NOIDA (U.P) 201301</OfficeAddress>
</item>
</office>
And I am trying to parse with TBXML parser.
Here my problem is, OfficeAddress value is accessible as a child element of item but text of <item> NOIDA OFFICE: is not getting parsed.
Its showing me text of <item> is NULL and showing only one child element <OfficeAddress> with associated text.
I want to parse NOIDA OFFICE: as item name. Anyone please help me, Advance appreciate on your help.
Happy coding :)
I think you are not able parse your XML. Please change the xml in server side like this.
<Office>
<item name=NOIDA OFFICE>
<OfficeAddress>B-20, SECTOR 57 NOIDA (U.P) 201301</OfficeAddress>
</item>
</Office>