In ColdFusion, I can parse a string of XML formatted data into an XML Object
using xmlParse(). How can I convert it back into a string?
When I tried using toString() it throws an error that "it can't convert complex object to simple objects....", which is ironic because that's what it's supposed to do.
I need to use XMLTransform() which requires the first argument to be an xml string. But I also need to use xmlSearch() to get a node to pass into my transform, and xmlSearch returns an xmlObject. So now I need to put that object back into xml string format to pass into xmlTransform.
Thank You - all;
The cause of my problem is that due to the structure of this particular XML, my XMLSearch returned an array with multiple items. So trying to use toString() on that result caused an error.
Code:
pXML = xmlParse( _xml );
myElements = XmlSearch( pXML, "//data" );
writeoutput( toString( myElements ) );
Result/Error:
Error Occurred While Processing Request
Complex object types cannot be converted to simple values.
Solution
writeOutput( toString( myElements[1] ) );
The XML has multiple nested nodes named "data", and XMLSearch() was traversing and returning each node.
Thanks again for you input.
I would wrap the XML in a cfsavecontent. And use the variable as a string
Try just outputing the XML text inside cfxml and then changing back into string format like so:
<cfxml variable="xmlObject" casesensitive="yes">
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
</rss>
</cfxml>
<cfoutput>#ToString(xmlObject)#</cfoutput>
OR
<cffile action="write" file="#ExpandPath('RSS.xml')#" output="#ToString(xmlObject)#">
For details on toString() http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f9e.html
If that's not what you need, could you clarify?
Related
I am stuck on an xquery for below request. I want to select the address based on the type value.
i.e. if type is "StreetAddress" then pick freeFormat "Maguire"
<associatedAddress>
<address xmlns="http://services.oracle.com/v1.0/Common">
<type xmlns="http://services.oracle.com/v1.0/Common">StreetAddress</type>
<freeFormat xmlns="http://services.oracle.com/v1.0/Common">Maguire</freeFormat>
</address>
<address>
<type xmlns="http://services.oracle.com/v1.0/Common">CityAddress</type>
<freeFormat xmlns="http://services.oracle.com/v1.0/Common">SanFransisco</freeFormat>
</address>
</associatedAddress>
I tried in couple of ways:
if associatedAddress/address/type="StreetAddress"
then.., But this one gives me only the first address
I also tried to use a for loop and then use if case inside it but even that gave me just the first address
Please let me know any other options. Thanks
The XPath for fetching value Maguire using the value in <type> is
<xsl:value-of select="associatedAddress/address[type='StreetAddress']/freeFormat" />
You need to take care of the namespace associated with the different elements in your input XML when fetching the value. If the namespace is not properly handled in the XSL, the value will not be extracted.
Since you asked for xQuery given your input xml, this:
declare namespace common="http://services.oracle.com/v1.0/Common";
for $n in associatedAddress//common:type[. = "StreetAddress"]
return
$n/../common:freeFormat
produces the desired result
<freeFormat xmlns="http://services.oracle.com/v1.0/Common">Maguire</freeFormat>
The trick is that in your input xml associatedAddress is not in the same namespace as the other elements, so you need to adjust your query to take this into account.
You mention an if clause, but its is not clear what the desired output is from your question. You can use the below as a template to modify results.
declare namespace common="http://services.oracle.com/v1.0/Common";
for $n in associatedAddress//common:type
return
switch($n)
case "StreetAddress" return $n/../common:freeFormat
case "CityAddress" return "something else"
default
return ()
I have created a function within a format.cfc component that returns a string without any HTML code in it:
<cffunction name="RemoveHTML" access="public" returntype="string" output="false" hint="Returns a string without any html">
<cfargument name="UserString" required="yes">
<cfset var result = "#REReplaceNoCase(Canonicalize(ARGUMENTS.UserString,false,true),'<[^>]*(?:>|$)', '', 'ALL')#">
<cfreturn result>
</cffunction>
I now want to split the string at each space and convert it into a list. So I tried using ValueList() and ListToArray() but they don't like the value returned from the function.
Using ValueList() I get an error saying:
Complex constructs are not supported with function ValueList
Or I get this error when using ListToArray:
Complex object types cannot be converted to simple values
I'm basically just doing this:
<!--- ValueList() --->
<title>#ValueList(Application.Format.RemoveHTML(UserString = rsProduct.Title), ' ')#</title>
<!--- ListToArray() --->
<title>#ListToArray(Application.Format.RemoveHTML(UserString = rsProduct.Title), ' ')#</title>
If I remove the ListToArray() or ValueList() function then I get back what I expect - a product title string with no HTML in it.
So why is the function not returning a string even though it looks like one? Or am I missing something completely obvious?
As others have noted in the comments, ValueList is designed to return a list of values that are contained in a column of a query object. It won't work with a string value.
ListToArray converts a list to an array. You can't then output an array in your HTML. So ListToArray is working fine, it's when you try to display it in a cfoutput that the error occurs.
It's a good idea to use the in-built encoding functions in CF, for example encodeForHTML. So you can do something like:
<title>#encodeForHTML(Application.Format.RemoveHTML(UserString = rsProduct.Title))#</title>
encodeForHTML, can accept an optional boolean 2nd argument (which is false by default), to indicate if you want to canonicalize the string. So you may want to do that instead of calling Canonicalize in your custom RemoveHTML function. After all your function is called RemoveHTML not RemoveHTMLAndCanonicalize :)
update
In response to OP's comment.
To get a comma delimited list from your 'space delimited' string, then you can use the replace function. Something like:
<title>#encodeForHTML(replace(RemoveHTML(rsProduct.Title), " ", ",", "all"))#</title>
You can of course, put the replace inside your custom function, I'm just demonstrating how it works.
You'll need to be aware, that it'll replace all spaces with a comma, so if you have 2 or more spaces in a row then it'll show ,, (depending on how many spaces). To get around that you can use a regular expression like so:
<title>#encodeForHTML(reReplace(RemoveHTML(rsProduct.Title), " +", ",", "all"))#</title>
You can also use listChangeDelims intead of reReplace as it ignores empty elements.
<title>#encodeForHTML(listChangeDelims(RemoveHTML(rsProduct.Title), ",", " "))#</title>
Personally I'd go with the regular expression version as it's more powerful, you'll want to wrap it up in a function though to keep the view nice and clean.
I think there are multiple ways to do this, consider below is my text
<cfset myText = "Samsung Galaxy Note 4"/>
first method by using simple replace function
<cfset firstSolution = replace(myText," ",",","all")/>
<cfdump var="#firstSolution#" />
Second method by using reReplace method
<cfset secondSolution = rEReplace(myText,"\s+",",","all")/>
<cfdump var="#secondSolution#" />
If I would be you I would have use second method cause if by any chance I have multiple spaces in my string then instead of getting multiple ',' I will get single ',' given string is used in the title of the page, I would not take any risk have incorrect title.
I have a XML like this
<Error>An error has occured while saving the workflow
<ErrorFile>C:\temp\Log\ErrorImages\accountwf38_1401351602333.png</ErrorFile>
</Error>
when I write an XSL transformation like this
<xsl:value-of select="Error"/>
I am getting the entire error value as output, including the error file value.
But I need only An error has occured while saving the workflow as output. How can I write a transformation for that?
Thanks
Rajendar
i am getting entire error value as output including error file value but i need only An error has occurred while saving the workflow as output
The <Error> element has three child nodes. A text node, an element (ErrorFile) node and another text node (containing a new line and some spaces before the end tag)`.
The XPath expression you used selects the entire Error node, which is converted to its string value when used in <xsl:value-of>, which consists of of all of its descendants converted to string.
To obtain what you need you can use this expression:
<xsl:value-of select="Error/text()"/>
which will select only the child text nodes.
And you can get rid of the unnecessary spaces using:
<xsl:value-of select="normalize-space(Error/text())"/>
I have the following XML snippet:
<figure customer="ABC DEF">
<image customer="ABC"/>
<image customer="XYZ"/>
</figure>
I'd like to check if the figure element's customer attribute contains the customer attributes of the image elements.
<xsl:if test="contains(#customer, image/#customer)">
...
</xsl:if>
I get an error saying:
a sequence of more than one item is not allowed as the second argument of contains
It's important to note that I cannot tell the values of the customer attributes in advance, thus using xsl:choose is not an option here.
Is it possible to solve this without using xsl:for-each?
In XSLT 2.0 you can use:
test="image/#customer/contains(../../#customer, .) = true()"
and you will get a true() result if any of them are true. Actually, that leads me to suggest:
test="some $cust in image/#customer satisfies contains(#customer, $cust)"
but that won't address the situation where the customer string is a subset of another customer string.
Therefore, perhaps this is best:
test="tokenize(#customer,'\s+') = image/#customer"
... as that will do a string-by-string comparison and give you true() if any of the tokenized values of the figure attribute is equal to one of the image attributes.
Using MSXML4, I am creating and saving an xml file:
MSXML2::IXMLDOMDocument2Ptr m_pXmlDoc;
//add some elements with data
SaveToDisk(static_cast<std::string>(m_pXmlDoc->xml));
I now need to acquire a substring from m_pXmlDoc->xml and save it. For example, if the full xml is:
<data>
<child1>
<A>data</A>
<One>data</One>
<B>data</B>
</child1>
</data>
I want to store this substring instead:
<A>data</A>
<One>data</One>
<B>data</B>
How do I get this substring using MXML4?
Use XPath queries. See the MSDN documentaion for querying nodes. Basically you need to call the selectNodes API with the appropriate XPath expression that matches the part of the DOM you are interested in.
// Query a node-set.
MSXML4::IXMLDOMNodeListPtr pnl = pXMLDom->selectNodes(L"//child/*");