Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Need help extracting text with XQuery/XPath 1

Status
Not open for further replies.

PPettit

IS-IT--Management
Sep 13, 2003
511
0
0
US
I've got some XML like this:
Code:
<?xml version="1.0"?>
<BTARNException xmlns:xsi="[URL unfurl="true"]http://www.w3.org/2001/XMLSchema-instance"[/URL] xmlns:xsd="[URL unfurl="true"]http://www.w3.org/2001/XMLSchema"[/URL] xmlns="[URL unfurl="true"]http://schemas.microsoft.com/biztalk/btarn/2004/BTARNException">[/URL]
  <ExceptionDescription>
    <errorClassification>
      <GlobalMessageExceptionCode>TimeoutOnSignal</GlobalMessageExceptionCode>
    </errorClassification>
    <errorDescription>
      <FreeFormText>Public initiator terminated on time out to receive a signal for the Async action message.</FreeFormText>
    </errorDescription>
    <offendingMessageComponent>
      <GlobalMessageComponentCode>PublicInitiatorProcess</GlobalMessageComponentCode>
    </offendingMessageComponent>
  </ExceptionDescription>
  <GlobalExceptionTypeCode>Exception Message</GlobalExceptionTypeCode>
</BTARNException>

I want the "FreeFormText" data ("Public initiator terminated ...) I've tried every XQuery/XPath statement I could think of but nothing's been working. It seems like this should work since I do something similar with a different bit of XML:
Code:
@xml.query('BTARNException/ExceptionDescription/errorDescription/FreeFormText/text()')
The only obvious difference is that the other file doesn't include the XML version tags.

What am I missing? If it helps to know, I'm working with the XML in a SQL stored procedure.
 
Most likely, you need to add the namespace to each of the nodes in the XPath expression. All of the nodes carry the default namespace declare by xmlns="
I am not an XQuery expert, so there may be a way to declare a default namespace for the XPath expression within XQuery. (There is not a way to do this in XSLT, so one must place a namespace alias on each node.)

Tom Morrison
Hill Country Software
 
Thanks for the suggestion. While investigating it, I found something that will work until I can figure out a better solution or learn more about XQuery/XPath.
Code:
@xml.query('/*/*/*/*[local-name()=''FreeFormText'']/text()')
If I understand it correctly, it's ignoring the namespace info, going down thee levels in the XML structure, searching for the specified node at the fourth level, then grabbing the text that it contains.
 
Looks like XPath 2.0 allows you to get rid of the "local-name()=''" stuff by replacing it with "*:". To me, it makes the code less bloated and easier to follow.
Code:
@xml.query('/*/*/*/*:FreeFormText/text()')
or even something like this:
Code:
@xml.query('/*:BTARNException/*:ExceptionDescription/*:errorDescription/*:FreeFormText/text()')
 
The '*' means 'any child'. You could also use the '//' operator, which means 'zero or more elements'. Your XPath expression could simply be:
Code:
//*[local-name()='FreeFormText']/text()
This would be translated to, "Give me the text out of all nodes named 'FreeFormText' without regard to namespace."

If there is a possibility of more than one, and you want only the first (for example), you would use this:
Code:
//*[local-name()='FreeFormText'][1]/text()
This would be translated to, "Give me the text out of the first node (in document order) named 'FreeFormText' without regard to namespace." 'Stacking' XPath predicates in this manner can be really convenient and can be far more complex than this.

Note also that predicates can apply to any node in the expression, not just the leaf node or the penultimate node.
Code:
/[highlight #FCE94F]*[/highlight]/[highlight #8AE234]*[1][/highlight]//*[highlight #F57900][local-name()='FreeFormText'][/highlight][highlight #BABDB6][1][/highlight]/[highlight #EF2929]text()[/highlight]
This would be translated to, "From the [highlight #8AE234]first child[/highlight] of the [highlight #FCE94F]document root element[/highlight], give me [highlight #EF2929]the text[/highlight] out of the [highlight #BABDB6]first node[/highlight] (in document order) [highlight #F57900]named 'FreeFormText' without regard to namespace[/highlight]." 'Stacking' XPath predicates in this manner can be really convenient and can be far more complex than this.

Not on point for this thread, but to complete the story a bit, one can also combine XPath predicates with the use of XPath axes to help identify nodes that have specific ancestor nodes, child nodes, or sibling nodes.

Tom Morrison
Hill Country Software
 
Oops, sorry for failing to trim the copy-and-paste in the previous post. [blush]

Tom Morrison
Hill Country Software
 
Thanks for the additional information. I can see it being useful in the near future.
 
PPettit said:
Looks like XPath 2.0 allows you ...

XPath 2 is not as well supported, so check on your specific platform. Unfortunate, but true.


Tom Morrison
Hill Country Software
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top