• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 248
  • Last Modified:

write to error string if xml child node is missing

How would I adjust the following so that if an xml child node is missing, it writes it to an error string.  So in other words, if its..

<x1>this</x1><x3>is</x3><x4>cool</x4>

I need to put into an error string (that I'll update to a db table) that xml child node <x2> is missing.  How would I do that?
<cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" step=1 index=i>
               <cfif isDefined('parsed.xmlRoot.co.x#i#.xmlText')>
<cfset mystring=mystring & #evaluate("parsed.xmlRoot.co.x#i#.xmlText")# & ','>
               <cfelse>
                  <cfset mystring=mystring &  ','>
               </cfif>
</cfloop>

Open in new window

0
COwebmaster
Asked:
COwebmaster
  • 19
  • 12
1 Solution
 
gdemariaCommented:

 <cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>


and don't use evaluate, instead you can do..


<cfset mystring=listAppend(mystring,  parsed.xmlRoot.co.['x' & i].xmlText")>

would replace this..

<cfset mystring=mystring & #evaluate("parsed.xmlRoot.co.x#i#.xmlText")# & ','>


listAppend will also manage the trailing comma for you

0
 
COwebmasterAuthor Commented:
gdemaria, there appears to be a missing double quoate in this line..
<cfset mystring=listAppend(mystring,  parsed.xmlRoot.co.['x' & i].xmlText")>

where would that other double quote go?

Also, I tried you're suggestion using  <cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>, but it only outputs the first node but skips the rest.  So, it only outputs..

this

Is should output..

this,is,cool (its missing node x2 which is 'so')
<cfset mystring="">
				
<cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" step=1 index=i>
               
<cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>
			   		
<cfset mystring=listAppend(mystring, #parsed.xmlRoot.co.['x' & i].xmlText#")>
		
</cfif>
</cfloop>
 
<cfset myString = Left(myString, Len(myString)-1)>
 
<cfoutput>#myString#</cfoutput>		
			

Open in new window

0
 
gdemariaCommented:
Sorry, that last quote should not have been in there, so the result would be...


<cfset mystring="">
<cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" index=i>
   <cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>
      <cfset mystring=listAppend(mystring, parsed.xmlRoot.co['x' & i].xmlText)>
   </cfif>
</cfloop>
 
<cfoutput>#myString#</cfoutput>         
       
                        

Open in new window

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
COwebmasterAuthor Commented:
gdemaria, ok I tried that but it still only returns the first node and no more.  It should return all nodes (except node 2)
0
 
COwebmasterAuthor Commented:
Also, how would I place a line break at the end of each iteration?  Would it be..

 #char(13)##char(10)#
0
 
gdemariaCommented:
Can you take an image of what this displays and post it pls..

<cfdump var="#parsed.xmlRoot.co#">



I don't think there is an "a" in chr() function..

  #chr(13)##chr(10)#
0
 
COwebmasterAuthor Commented:
actually, I think I have the line break and carriage return working.

I just did..

<cfset myString = Left(myString, Len(myString)-1)>
<cfset myString = Replace(myString, chr(10) & chr(13), "", "ALL")>
0
 
COwebmasterAuthor Commented:
the dump just displays the first child node:

this,
0
 
gdemariaCommented:
> the dump just displays the first child node

then that's all the data that's in the XML, so the myString value is correct.
If the dump of the XML structure showed all three, then so should myString, but since it only showed one "this" then it matches myString and myString is right.

>   <cfset myString = Left(myString, Len(myString)-1)>

why do you still have this?   Since you're now using listAppend, it will truncate off the last character.

> <cfset myString = Replace(myString, chr(10) & chr(13), "", "ALL")>

this will remove any carriage returns


Can you post your code as it looks now, It doesn't seem you're using my version..
0
 
COwebmasterAuthor Commented:
Ok, so this what I have.  So if a chiild node is missing (<x2> in this example), the first node is in the output file only, not the rest (node 3 and 4 are not there) using your example above.
<cfloop query=qcosToProcess>
			<cfset xmlString="#orderString#">
			<cfif isXML(xmlString)>
			<!--- Ok, it's XML, now parse the record and create output to file! --->
				<cfset parsed=XmlParse(xmlString)>
				<!--- Ok, now make sure parent node is good! --->
				<cfif structKeyExists(parsed.xmlRoot, "co")>
					
					<cfset mystring="">
				
					<cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" step=1 index=i>
               			
						<cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>
      						<cfset mystring=mystring & #evaluate("parsed.xmlRoot.co.x#i#.xmlText")# & ','>
   						</cfif>
						
					</cfloop>
					
					<!--- remove trailing comma --->
					<cfset myString = Left(myString, Len(myString)-1)>
					
					<!--- carriage return at end of each line --->
					<cfset myString = Replace(myString, chr(10) & chr(13), "", "ALL")>
					
					<!--- output to file --->
					<cffile action="append" addNewLine="yes" file="[filename]" output="#mystring#">				
 
					<!--- now, update the record! --->
					<cfquery name="updco" datasource="[dsn]">
		   			[update qry]
		        	</cfquery>
				
				<cfelse>
				use cfmail..
				</cfif>
				
			<cfelse>
			use cfmail..
			</cfif>
</cfloop>
 
<cfelse>
no records!
</cfif>

Open in new window

0
 
COwebmasterAuthor Commented:
I tried using <cfset mystring=listAppend(mystring, parsed.xmlRoot.co.['x' & i].xmlText)> but I get an error which says..

Missing argument name.
 
0
 
COwebmasterAuthor Commented:
so using <cfset myString = Replace(myString, chr(10) & chr(13), "", "ALL")> will remove all carriage returns (after each record) and do a line break after each record, yes?
0
 
gdemariaCommented:
> but I get an error which says..

there is a . after co which I removed in the second post.  

> so using <cfset myString = Replace(myString, chr(10) & chr(13), "", "ALL")> will remove all carriage returns (after each record) and do a line break after each record, yes?

No, replace takes locates the second argument and replaces it with the third arguments.   so if you had   replace("abacadaf", "a",  "", "all") the result would be  "bcdf"  ...  you are removing all carriage returns

Your carriage return is being added in your file by the parameter..

<cffile action="append" addNewLine="yes"  <=====


Please cut and paste in this code to replace the appropriate block of code..

<cfif structKeyExists(parsed.xmlRoot, "co")>
  <cfdump var="#parsed.xmlRoot.co#">
  <cfset mystring="">
  <cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" index="i">
    <cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>
        <cfset mystring= listAppend(mystring, parsed.xmlRoot.co["x#i#"].xmlText)>
    </cfif>
  </cfloop>
  <cffile action="append" addNewLine="yes" file="[filename]" output="#mystring#">                         
  <cfquery name="updco" datasource="[dsn]">
   [update qry]
  </cfquery>
<cfelse>
 use cfmail..
</cfif>

Open in new window

0
 
COwebmasterAuthor Commented:
I need to remove all line breaks and carriage returns from each record output.  How would do that?  I'll try what you have here.
0
 
gdemariaCommented:
There won't be any carriage returns in myString, unless they are part of the XML data x2, x3, etc..   If those values contain carriage returns, they need to be cleaned earlier.

<cffile action="append" addNewLine="no"  <=== change this to NO in order not to write a carriage return
0
 
COwebmasterAuthor Commented:
If I change it to no, then the output of all records is one long string.

Ok, I tried your example and the output is the first node only.  It should display all nodes even if a node is missing.
0
 
COwebmasterAuthor Commented:
sorry, my bad.  the records have to have a carriage return between each record iteration.  Setting that to yes will place a line break after each record, but will that also give it a carriage return?
0
 
gdemariaCommented:
i think line break and carriage return are used interchangeably; they are the same thing in this case.
0
 
gdemariaCommented:
> Ok, I tried your example and the output is the first node only.  It should display all nodes even if a node is missing.

Previously, you had said that the result of the <cfdump> command showed only one node.  That dump from the XML structure,  if there is only one item in the XML structure, then myString will also only have one item...  The code appears to be working correctly, you have to look at your XML to see that it has what you think it has...

<cfdump var="#parsed.xmlRoot.co#">

If this dump only shows one item, then that is all that will end up in your file
0
 
COwebmasterAuthor Commented:
In my table, I have <x1>this</x1><x3>is</x3><x4>cool</x4>

It's missing node 2.  however, the output file should still loop through each node and output each node irregardless if a node is missing.  i think because its missing node 2, it's not moving past node 1 and not writing nodes 3 and 4
0
 
gdemariaCommented:

You are looping through whatever is in the variable xmlString

<cfif isXML(xmlString)>

which becomes "parsed" ...
      <cfset parsed=XmlParse(xmlString)>

and then you examine the xmlRoot for an element called "co"...

<cfif structKeyExists(parsed.xmlRoot, "co")>


here you display the contents of "co" ...
  <cfdump var="#parsed.xmlRoot.co#">


You told me that this displayed only one element  "this" ...

if that is true, then the rest of the code doesn't matter, you only have one element.


Try dumping this to see if you can find more than one element..
<cfdump var="#parsed#">

If not, you have to look at your source, because it's there...
0
 
COwebmasterAuthor Commented:
This should take care of the line break and carriage return after each record, yes?

<cfset variables.CrLf = Chr(13) & Chr(10)>
<cfset mystring=mystring & variables.CrLf>
                              
<cffile action="append" addNewLine="no" file="[filename]" output="#mystring#">
0
 
COwebmasterAuthor Commented:
Ok, I added in <cfdump var="#parsed.xmlRoot.co#"> where you mentioned and the output displays..

<x1>this</x1>
<x3>is</x3>
<x4>cool</x4>

So, that's correct.  However, the output file, what is written is only the first node 'this'.  Why isn't is writing the other nodes into the file?
0
 
COwebmasterAuthor Commented:
Ok, so did a dump here..

<cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" step=1 index=i>
<cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>
<cfset mystring=listAppend(mystring, parsed.xmlRoot.co["x#i#"].xmlText)>
</cfif>
</cfloop>
<cfdump var="#mystring#">

and it outputs only the node 1, not nodes 1,3,4 which it should
0
 
COwebmasterAuthor Commented:
i guess the problem is that it's not looping through each node and appending it to mystring after it finds a node missing.
0
 
COwebmasterAuthor Commented:
How would I loop through each node using the following and output to mystring only the nodes that are present?
<cfloop from=1 to="#arrayLen(parsed.xmlRoot.co.xmlChildren)#" index=i>
               			
<cfif structKeyExists(parsed.xmlRoot.co, "x#i#")>
<cfset mystring=listAppend(mystring, parsed.xmlRoot.co["x#i#"].xmlText)>
</cfif>
 
</cfloop>

Open in new window

0
 
gdemariaCommented:
>  Ok, I added in <cfdump var="#parsed.xmlRoot.co#"> where you mentioned and the output displays..

<x1>this</x1>
<x3>is</x3>
<x4>cool</x4>



If that is true, then the dump is not showing parsed XML format.  That is why the CFIF is not matching.   After using the parse XML function, the output should no longer have the <x1> etc  tags in it... it should be a structure.

Is that exactly what is being shown by the dump?

The problem seems to be parsing..


0
 
COwebmasterAuthor Commented:
yes, I don't know.  The dump looks good, but for some reason, it's not outputting the correct nodes to the file.
0
 
gdemariaCommented:
No, I'm saying the dump is not good.  
After doing the XML parse you should NOT see this:

<x1>this</x1>
<x3>is</x3>
<x4>cool</x4>

the xml parse transitions the xml into a coldfusion structure, if you don't see a dump of a structure, then the problem is not the simple CFLOOP it's the XML source which is not being interpretted as XML and is not parsing into the structure as it should

0
 
gdemariaCommented:

I recommend accepting:  ID:24159546  Author:gdemaria

The thread went over several different topics, but this addresses the original question of how to loop over the XML
0
 
COwebmasterAuthor Commented:
Thanks!
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 19
  • 12
Tackle projects and never again get stuck behind a technical roadblock.
Join Now