how to write a CDATA node using libxml2? - libxml2

I'm using libxml2 to read/write xml files. Now I'm trying to write a CDATA node.
Here is what I tried:
nodePtr = xmlNewChild( parentPtr, NULL, "foo", NULL );
xmlNodeSetContentLen( nodePtr, "<![CDATA[\nTesting 1 < 2\n]]>", len );
However, this results in the following encoded text:
<foo><![CDATA[
Testing 1 < 2
]]></foo>
I'm thinking that perhaps there might be a CDATA-specific libxml2 API. Or maybe I have to call something else to tell libxml2 not to automatically encode the node content?

Figured it out. The trick is in knowing that CDATA text content is actually a child and not a part of the current node, and the critical API to call is xmlNewCDataBlock(). Using the same example as above:
nodePtr = xmlNewChild( parentPtr, NULL, "foo", NULL );
cdataPtr = xmlNewCDataBlock( doc, "Testing 1 < 2", 13 );
xmlAddChild( nodePtr, cdataPtr );
This will produce the following xml:
<foo><![CDATA[Testing 1 < 2]]></foo>

I cannot say for all versions of libxml2, but according to libxml2-2.9.4 the doc part of returning node of xmlNewChild comes from its parent. Also the parent of child node returned from xmlNewCDataBlock is set by doc parameter. So the following would be a good practice:
const char str[] = "said the kitty";
xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "meow");
xmlNodePtr cdata_node = xmlNewCDataBlock(node->doc, BAD_CAST str, strlen(str));
xmlAddChild(node, cdata_node);
The resulting xml is
<meow><![CDATA[said the kitty]]></meow>
And it would not matter if node is part of an xmlDoc or not

Related

Passing javascript string variable into nlapiSearchRecord filter

I'm working on a Suitelet to apply landed costs (through a .csv file) to item receipts. This code below is iterating through an array of PO numbers to build out a formula(number) to pass into nlapiSearchRecord().
I'm having trouble getting the search to fire when passing part of the search filter in from a variable. I've tried passing various sizes of string with and without double or single quotes (see commented out sections for an idea) and now I'm simply passing one variable, testNumber, into the search string. It's still failing giving me this error:
SSS_INVALID_SRCH_FILTER_EXPR_OBJ_TYPEMalformed search filter expression: Unrecognized object type.
The complete line is supposed to be
["formulanumeric: case when {number} = 'PO476' or {number} = '294' then 1 else 2 end","equalto","1"],
for(var i = 0; i<poNumbers.length; i++) {
if(i < (poNumbers.length - 1)) {
poFormula += "{number} = '"+poNumbers[i]+"' or ";
}
else {
poFormula += "{number} = '"+poNumbers[i]+"'";
}
}
//poFormula(string) --> {number} = 'PO481' or {number} = 'PO476' or {number} = '294' or {number} = 'PO440' or {number} = 'PO441'
//var searchFormulaStart = "formulanumeric: case when "+poFormula+" then 1 else 2 end";
//var sfMiddle = "equalto";
//var sfEnd = "1";
var testNumber = "'PO476'";
var purchaseorderSearch = nlapiSearchRecord("purchaseorder",null,
[
["mainline","is","T"],
"AND",
["type","anyof","PurchOrd"],
"AND",
["formulanumeric: case when {number} = "+testNumber+" then 1 else 2 end","equalto","1"],
//[searchFormulaStart,sfMiddle,sfEnd],
"AND",
["type","anyof","PurchOrd"]
],
[
new nlobjSearchColumn("internalid",null,null)
]
);
The idea is that I need to return all the POs included in the .csv so I can get their internal ids. Later in the code, I will pass these ids into another search against item receipts, finding all receipts created from those POs. Once I have those, I can apply freight costs to those receipts.
var itemreceiptSearch = nlapiSearchRecord("itemreceipt",null,
[
["type","anyof","ItemRcpt"],
"AND",
["mainline","is","T"],
"AND",
["createdfrom","anyof", poInternalIds]
],
[
new nlobjSearchColumn("tranid",null,null)
]
);
Can anyone confirm if there's some undocumented bug or something with passing part of a search string in from a variable like this? Alternatively, given PO numbers and freight costs, is there a better way to apply landed costs to item receipts?
Thanks!
I found a solution with help from some folks on Slack. Rather than trying to concatenate variables into the filter string, I'm now creating the entire filter array in a forEach() loop as shown below.
I'm still not sure why the Netsuite API didn't like my search formatted with a concatenation, but this is a much cleaner solution anyway.
for(var i = 0; i<freightCosts.length; i++) {
poNumbers.push(freightCosts[i].PO);
}
poNumbers.forEach(function(tranid){
filters.push(["tranid", "is", tranid]);
filters.push("or");
});
// remove the last "or"
filters.pop();
var purchaseorderSearch = nlapiSearchRecord("purchaseorder",null,
[
["mainline","is","T"],
"AND",
["type","anyof","PurchOrd"],
"AND",
[filters]
],
[
new nlobjSearchColumn("internalid",null,null)
]
);
Weirdly enough, I ran into this exact issue just last week. It appears to be a bug in the Rhino Javascript engine that Netsuite uses. The workaround to get it to work is to wrap your concatenation in a String():
[String("formulanumeric: case when {number} = "+ testNumber + " then 1 else 2 end"), "equalto", "1"]

Set inner HTML using QDomDocument

How can I set the inner HTML in a QDomElement?
When I’m using QWebElement I have the method QWebElement::setInnerXml, there is some similar method in QDomElement?
There's no API to "inject" XML snippets as text into a QDomDocument (or QXmlStreamWriter). One has to use the API and create the nodes programmatically.
Assuming you have a string to start with, my current solution is to generate a DOM tree from it, import that tree in a fragment, then copy those in the right place (you must have an import which is why you need an intermediate fragment. Quite unfortunate if you ask me.)
// assuming that 'n' is the node you are replacing or at least inserting after
// 'parent' is the parent of 'n'
// 'result' is the string to replace 'n' or insert after 'n'
QDomDocument doc_text("snap");
doc_text.setContent("<text>" + result + "</text>", true, NULL, NULL, NULL);
QDomDocumentFragment frag(xml.createDocumentFragment());
frag.appendChild(xml.importNode(doc_text.documentElement(), true));
QDomNodeList children(frag.firstChild().childNodes());
const int max(children.size());
QDomNode previous(n);
for(int i(0); i < max; ++i)
{
QDomNode l(children.at(0));
parent.insertAfter(children.at(0), previous);
previous = l;
}
// if you are replacing, then delete node n as well
parent.removeChild(n);
Note that the <text> tag is used so that way result does not need to be a tag, it could just be text and it will still work.
Obviously, if you have a fragment or XML from another document to start with, ignore the code that creates that code in the doc_text object.

adobe acrobat XI pro javascript

i am calling an javascript function when out of focus on the form field. So what i am tying to do is the if i ticked required this field as required field it will have a red border around it, can i write a script to remove the required option when there are value inside the field?
var thisValue = this.getField("companyName").value;
var regexLetter = /[A-Z]+$/;
var Icon = "0"; //0 — Error (default) // 1 — Warning // 2 — Question // 3 — Status
var Type = "0"; //0 — OK (default) // 1 — OK, Cancel // 2 — Yes, No // 3 — Yes, No, Cancel
if (thisValue == ""){
app.alert({
cMsg:"this is an warning",
cTitle: "thsi is title",
nIcon: Icon,
nType: Type
})
} else if(!regexLetter.test(thisValue)){
app.alert('Type alphanumeric character');
}
This is going to be rather late, but this is how I do it in my documents:
var _companyName = this.getField("CompanyName");
_companyName.required = (_companyName.value === "");
You can also impose other dependencies, like:
var _companyName = this.getField("CompanyName"),
_companyLicense = this.getField("CompanyLicense");
_companyLicense = ((_companyLicense === "")
&& (_companyName !== ""));
Having your scripts split into a couple of files could help. I use a "shared" script which contains a vast majority of the logic and the a "specific" script to round of each individual document. Also, make sure when adding the scripts to just name them 1, 2, 3, etc. in the correct order or Acrobat will be stupid. Hope this helps you.

Using List of (T) with Lucene.net in vb.net

i want to use an List to store the title, path,... from Documents.
I declared the list like this:
Dim MyDocuments As New List(Of Document)
But i don't really know how to handle the list.
i want to use the list instead of an ReDim Array.
For i = 0 To results - 1 Step 1 ' forschleife zum durchlaufen der Ergebnisse
Try
MyDocuments.Add(New Document())
array_results(i, 0) = hits.Doc(i).Get("title")
array_results(i, 0) += hits.Doc(i).Get("doc_typ")
array_results(i, 1) = hits.Doc(i).Get("pfad")
'array_results(i, 2) = hits.Doc(i).Get("date_of_create") '
array_results(i, 2) = hits.Doc(i).Get("last_change")
array_results(i, 3) = CStr(hits.Score(i))
array_results(i, 4) = hits.Doc(i).Get("doc_typ")
Can I store the object Document, or do i have to create an own class??
Is there a good tutorial for using the list? (i searched, but didn't found something good)
Is the List of (T) the right data structure?
but how can i do like mylist(i) ->gettitle() or something like this?
thanks in advance!
Yes, you can store your documents in a generic List. Deciding if a List<T> is the right data structure or not depends on what you want to do with it. Maybe if you provide more information someone could come up with a better example. I don't know VB.NET so i'll do it in C#.
// i assume you're using the Document class of Lucene.NET
List<Document> documents = new List<Document>();
// add the documents to your collection
for (i = 0; i < hits.Length(); i++)
{
// each result in the list contains a Document
// which you can add to your list
documents.Add(hits.Doc(i));
}
// you can search the list for a Document following a specific rule, using lambda expressions
Document myDoc = documents.Find(d => d.Get("title") == "a value");
// you can get a document by a specific index
Document myOtherDoc = documents[0];
// you can search the list for multiple Documents following a specific rule, using lambda expressions
List<Document> myDocs = documents.FindAll(d => d.Get("doc_typ") == "a type");
More information about the List<T> can be found here: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx
More information on lambda expressions can be found here: http://msdn.microsoft.com/en-us/library/bb397687.aspx
This article on SO shows how to use lambdas to search a List<T>

Changes to one variable propagates to another

For example I have two ArrayCollection's - firstAC and secondAC. If I do secondAC = firstAC, and than I make changes to secondAC (prehaps put a filterfunction on it) it somehow propagates to firstAC, would anyone tell me why that happens in Flex or Actionscript 3?
What can I do if I only want secondAC to get all data from firstAC but then when I make changes to secondAC it does not show in firstAC?
Thanxs a bunch for answers!
Ladislav
When you write secondAC = firstAC, you simply state that secondAC and firstAC are references to the same array collection.
What you want is to clone the first collection (as in, copy all elements one by one).
You should be able to do it with something like :
secondAC = new ArrayCollection();
secondAC.addAll(firstAC);
I have no idea of Flex or Actionscript, but looks like firstAC and secondAC point to the same array, therefore that's expected.
What you should do is just create another array, copy members, and they will be two real different entities.
Instead of secondAC = firstAC, you can try secondAC.addAll(firstAC).
In ECMAScript languages (AS1-3, JavaScript, et al.), when you use
var foo = //some value which is not a String or a Number
what you are really saying is "foo now points to the same object as that other variable." This means that in this situation, both arrays will be the same value:
var foo:Array = [ 1, 2, 3 ];
foo = bar;
bar.push( 4 );
trace( foo ); // 1, 2, 3, 4
This also works for functions:
var foo:Array = [ 1, 2, 3 ];
adder( foo );
function adder( bar:Array ):void {
bar.push( 4 );
}
trace( foo ); // 1, 2, 3, 4
and it even works with XML:
var xml:XML = <root><foo/></root>;
var bar:XML = xml;
bar.children()[ 0 ].#bar = 1;
trace( xml.toXMLString() ); // <root><foo bar="1"/></root>
This is called "passing by reference" instead of "passing by value" or "passing by copy". It means that every time that an item is referenced, each variable will point to the same object.
There are many ways to get around this, and most of them depend on your context. For arrays, my favorite is Array.concat(), which returns a literal clone of the array. This means that anything I do to the returned value will not effect the original in any way. If I'm dealing with XML, however, I will do something like: var xml2:XML = XML( xml.toXMLString() );.
In your case, I would actually recommend that you use:
var secondAC:ArrayCollection = new ArrayCollection( firstAC.source.concat() );
This has the major benefits of not only being faster (it relies on compiled code instead of Flex SDK code and it also does not first instantiate a new array and then re-populate it), but it also has the distinct benefit of being available in older versions of Flex 3's SDK -- it is entirely backwards compatible.

Resources