I work at a veterinary hospital and am generating xml from an IBM UniVerse DB which may or may not contain multi-valued data, and parsing/displaying it via CF8. I have written custom java classes take the user input from the cfform, handle the db transactions and pass back an xml object which is then parsed in CF. (the multi-value data driver does funky things with the data and causes CF to drop the connection intermittently.)
<MAIN _ID = "1081693">
<LAST_MV LAST = "MALLIK"/>
<FIRST_MV FIRST = "A.K. BOBBY"/>
<AN_NAME_MV AN_NAME = "BOTAR"/>
<AN_NAME_MV AN_NAME = "BONES"/>
<AN_BREED_MV AN_BREED = "MIXB"/>
<AN_BREED_MV AN_BREED = "GERM"/>
<ADDRESS_MV ADDRESS = "555 HAPPY ST"/>
<ADDRESS_MV/>
<CITY_MV CITY = "PHILADELPHIA"/>
<AN_NUM_MV AN_NUM = "647873"/>
<AN_NUM_MV AN_NUM = "645692"/>
</MAIN>
<MAIN _ID = "1173319">
<LAST_MV LAST = "MALLIK"/>
<FIRST_MV FIRST = "JOE"/>
<AN_NAME_MV AN_NAME = "SMOKEY"/>
<AN_BREED_MV AN_BREED = "MIXB"/>
<ADDRESS_MV ADDRESS = "512 SAD ST "/>
<ADDRESS_MV/>
<CITY_MV CITY = "PHILADELPHIA"/>
<AN_NUM_MV AN_NUM = "762268"/>
</MAIN>
</ROOT>
Notice that the first owner has two animals, listing the name, breed, and animal number (respectively), while the second owner has one. I am having the worst time building a query object from this xml. We don't know how many animals a given owner will have. The query object may repeat the owner info, which is fine, as the "key" needs to be the animal number. Any tips would be extremely helpful and greatly appreciated. Thank you.
You could move all this data into one query, but I am not sure if that would help you all that much. While you can build queries manually, any way you want, we should probably try to stick to "better practices" when it comes to database table creation. That being said, when I see your XML data, I see two different queries: one for customers and one for pets. Doing this gives us the ability to create multiple pets for a single customer and then relating them in a one-to-many relationship without having to unnecessarily duplicate data.
To do this, we are going to create a customer table with the following fields:
Then, we are going to have a pets table with the following fields:
Here, it is the "customer_id" column that relates the pet back to the customer table. The customer_id is the foreign key constraint that matches the "id" column of the customer table. Doing this allows you to access the data in a more dynamic and flexible way.
The plan is easy, but getting the XML data into the query is not so easy. It's not too complicated, it just take a lot of foot work and elbow grease. We're going to be using XPath() to search for nodes and then take that node data and populating the various queries. The tricky thing about working with XML data (especially for ME working in an unknown system) is that we can't always be sure WHAT data will always exist. While not all of this is up in the air, since I have never worked with this system or with an IBM UniVerse Database, I am putting potentially excessive "existence checking" for many of the nodes and attribute values. If you know that these nodes will always be there, then you can take a lot of the CFIF logic out.
That being said, here is my solution:
Launch code in new window » Download code as text file »
Running the code, you can see that we get our two populated ColdFusion query tables:
| | | | ||
| | ![]() | | ||
| | | |
Now that we have this data, we can start to access it. You can either query each table individually, or join the two tables to get related information as in this example:
Launch code in new window » Download code as text file »
Running the above code, we get the following CFDump output:
| | | | ||
| | ![]() | | ||
| | | |
XML is a really great data transportation language and XPath() support in ColdFusion makes it fairly easy to work with; but, it's still very labor intensive. ColdFusion 8 has added additional support for XPath() to make it even easier. I hope that this has helped in some way.
Download Code Snippet ZIP File
Comments (5) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
Wow. I'd gotten so stuck on the idea of continuing the multi-value flow from the db, it hadn't occurred to me to normalize it post-xml. Your solution has helped me greatly, and spared me from pulling the few hairs I have left. Thank you so much.
Posted by Chris Dunbar on Dec 21, 2007 at 11:49 AM
@Chris,
Glad to help :) Working with XML is mostly grunt work - once you get it into nice queries, you can really access it easily.
For anyone else interested, there is some ColdFusion 8 only stuff, but all of it can be easily modified to work with ColdFusion 7.
Posted by Ben Nadel on Dec 21, 2007 at 11:51 AM
There is also a rather handy tags that convert XML to cf structures for easier handling.
CFX_XML
http://www.adobe.com/cfusion/exchange/index.cfm?event=extensionDetail&extid=1002711
CF_EASYXML
http://www.adobe.com/cfusion/exchange/index.cfm?event=extensionDetail&extid=1019203
Posted by Russ Michaels on Jan 10, 2008 at 3:21 PM
Hi Ben;
This is exactly what i need. Thanks. But I am getting a loop error
Attribute validation error for tag CFLOOP.
The tag does not allow the attribute(s) ARRAY. The valid attribute(s) are COLLECTION,CONDITION,DELIMITERS,ENDROW,FROM,INDEX,ITEM,LIST,QUERY,STARTROW,STEP,TO.
Please try the following:
Enable Robust Exception Information to provide greater detail about the source of errors. In the Administrator, click Debugging & Logging > Debugging Settings, and select the Robust Exception Information option.
Check the ColdFusion documentation to verify that you are using the correct syntax.
Search the Knowledge Base to find a solution to your problem.
Browser Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Tablet PC 1.7; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Remote Address 127.0.0.1
Referrer
Date/Time 20-Apr-08 12:00 PM
Is there a way to resolve this?
Thanks
Lakshmi
Posted by Lakshmi Prayaga on Apr 20, 2008 at 1:05 PM
@Lakshmi,
The "Array" attribute is a ColdFusion 8 feature. If you are pre-ColdFusion 8, you have to convert the array loop into an index loop:
<cfloop
index="xmlMainNode"
array="#arrMainNodes#">
... becomes:
<cfloop
index="intNodeIndex"
from="1"
to="#ArrayLen( arrMainNodes )#"
step="1">
<cfset xmlMainNode = arrMainNodes[ intNodeIndex ] />
Hope that helps.
Posted by Ben Nadel on Apr 21, 2008 at 9:43 AM