XQuery: Inserting Nodes - xquery

I'm reading in an XML file using XQuery and want to insert several nodes/elements and generate a new XML file. How can I accomplish this?
I've tried using the replace() function, but, it looks like all my XML tags are being stripped when I call doc() to load my document. So calling replace() isn't any good if my XML tags are being removed.
Any help? Are there other technologies I can use?

An extension to the XQuery language allowing updates -- the XQuery Update Facility -- exists to allow documents to be modified.
Inserting a node looks like this:
insert node <foo>bar</foo>
into /bar//baz[id='qux']
Among other engines, this is supported by BaseX.
See http://www.w3.org/TR/xquery-update-10/

replace() is a string operation, so the XML will be converted to a string before replacement.
To create a modified copy of the original file, you can modify an identity transformation which recursively copies the original file to insert the new nodes where required - see the article in the XQuery Wikibook
Alternatively if the file is in an XML database such as eXist, you can use update operations to insert elements in situ.

Using XQuery Scripting you can write programs like this:
variable $stores := doc("stores.xml")/stores;
insert node element store {
element store-number { 4 },
element state { "CA" }
} into $stores;
$stores
You can try such example live at http://www.zorba-xquery.com/html/demo#vpshT+pVURyQSCEOKrFBrF0jyGY=

Related

XQuery file returning invalid entity reference using special characters

I have the following query in a MarkLogic XQuery file, and I am seeing the following error message returned
XDMP-ENTITYREF: (err:XPST0003) Invalid entity reference " " . See the MarkLogic server error log for further detail.
The following is the code I am using in the XQuery file.
xquery version "1.0-ml";
declare variable $query :=
cts:or-query
((
cts:element-word-query(xs:QName("lines"),"l&l"),
cts:element-word-query(xs:QName("lines"),"pool & cue"),
cts:element-word-query(xs:QName("lines"),"look")
));
declare function local:do-query(){
element xml {
for $i in cts:uris( (), (), $query)
let $item := doc($i)
return
element item {
element title { $item/title/string() }
}
}
};
local:do-query()
Obviously the 2x tags i am looking for are l&l and pool & cue. I have also looked into the repair-full suggestion in another question posted, but couldn't figure out how that fits into this query. If I removed the ones with special characters, it works as expected.
Any ideas?
Based on the additional info in the comments to the question, this is not an issue with the execution of the code, but rather with deployment of the code.
This happens often if you insert code using QConsole, or some other ways in which you evaluate XQuery code. The & get interpreted, and translated to the & character it represents. If you then write that into a .xqy file into some Modules database, it does not get escaped back into & again, since XQuery files are stored as plain text in MarkLogic, and & doesn't get escaped in plain text.
A better way to deploy code is by uploading or inserting from disk. That way characters like &, >, and { inside XML won't get interpreted, but preserved and inserted as is. There are tools like ml-gradle and Roxy that make deploying MarkLogic code very easy. Consider using these. Alternatively you could also look into using Curl against the Management REST api.
If you want to use QConsole after all, escape characters like & twice. E.g. & becomes &amp;, and < becomes &lt;.
HTH!

OSB reporting, report multiple content. $body, $inbound, $outbound

I am trying to put multiple values inside this content with this XQuery Expression Builder. I tried to use a string function like thisfn:concat($body, $inbound, $inbound), but this does not seems to keep the whole message.
Is there any way that I can put all these variables in one report action? If this is possble then how should I read these values out after they are stored in the database(some key value structure would be perfect).
You only need to form a xml with the content you want to show in your report:
<report>
<body>{$body}</body>
<inbound>{$inbound}</inbound>
...
</report>
the only requirement is that the output have to be an XML no matter the structure.
Not sure, but I would try something like this:
<myroot>{$body, $inbound, $outbound}</myroot>
Or if you really need a string returned:
fn:serialize(<myroot>{$body, $inbound, $outbound}</myroot>)
Note, fn:serialize is only in OSB 12c+.

How can I find documents accessed to answer my Xquery query?

I have the following objective. I want to find, which documents contain my data when executing any kind of Xquery or XPath. In other words, I need every document that is providing me the result data for a given query. I try to do this in eXist-db environment, but I suppose there should be something on Xquery level.
I found op:context-document() operator which seems to have functionality I want, yet, as an operator it is not available for me. fn:document-uri also does not do the trick, as its $arg must be a document node, otherwise it returns an empty sequence.
Do you have any idea in mind? All the assistance is highly appreciated.
fn:base-uri() may help; it returns the base URI property of a node:
for $d in doc('....')/your[query]
return base-uri($d)
You can also use it to filter your documents for specific types:
collection('/path/to/documents')[ends-with(base-uri(), '.xml')]
Use the standard XPath / XQuery function collection() .
For example, using Saxon:
collection('file:///a/b/c/d?select=*.xml')[yourBooleanExpression]
selects the document nodes of all XML documents, residing in the /a/b/c/d directory of the filesystem, that satisfy your criteria (yourBooleanExpression evaluates to true())

how to check whether a file exists before creating it

I am creating an xml file. I need to check first if the file exists or not. If the file does not exist, create it and add the data cmg from a .cs file.
If the file exists, don't create the file just add the data cmg from a .cs file.
My code looks like this:
string filename="c:\\employee.xml";
XmlTextWriter tw=new XmlTextWriter(filename,null);//null represents
the Encoding Type//
tw.Formatting=Formatting.Indented; //for xml tags to be indented//
tw.WriteStartDocument(); //Indicates the starting of document (Required)//
tw.WriteStartElement("Employees");
tw.WriteStartElement("Employee","Genius");
tw.WriteStartElement("EmpID","1");
tw.WriteAttributeString("Name","krishnan");
tw.WriteElementString("Designation","Software Developer");
tw.WriteElementString("FullName","krishnan Lakshmipuram Narayanan");
tw.WriteEndElement();
tw.WriteEndElement();
tw.WriteEndDocument();
tw.Flush();
tw.Close();
so next time we add data to file we need to check if the file exits and add data to xml file
and as we have made empID as a primary key, if user tries to make duplicate entry we need to avoid
Is this possible to do?
if (!File.Exists(filename))
{
// create your file
}
or
if (File.Exists(filename))
{
File.Delete(filename);
}
// then create your file
File class is in System.IO namespace (add using System.IO; to your file)
You can't append records to an XML file, you have to read the file and then rewrite it.
So, just check if the file exists, and read the records from it. Then write the file including all previous records and the new record.
Have a look at the File.Exists method here
Testing for existance of a file before attempting to create it inherently is subject to a "things change after check" race condition. Who can guarantee you that your application isn't preempted and put to sleep for a moment after you checked, someone else creates/deletes that file, your app gets to run again and does exactly the opposite of what you intended ?
Windows (as well as all UN*X variants) supports file open/create modes that allow to perform that create-if-nonexistant/open-if-existant operation as a single call.
As far as .NET goes, this means for your task (create an XML file) you'd first create a System.IO.FileStream with the appropriate modes, see http://msdn.microsoft.com/en-us/library/system.io.filemode.aspx and then pass that stream to the XmlWriter constructor. That's safer than simply performing an "exists" check and hoping for the best.

Best method to populate XML from SQL query in ASP.NET?

I need to create a service that will return XML containing data from the database. So I am thinking about using an ASHX that will accept things like date range and POST an XML file back. I have dealt with pages pulling data from SQL Server and populating into a datagrid for visual display but never into XML for delivery, what is the best way to do this? Also if an ASHX and POST isn't the best method for delivery let me know... thanks!
EDIT: These answers are great and pointing me in the right direction. I should have also mentioned that the XML format has already been decided so I can't use any automatically generated one.
Combining linq2sqlwith the XElement classes, something along the lines:
var xmlContacts =
new XElement("contacts",
(from c in context.Contacts
select new XElement("contact",
new XElement
{
new XElement("name", c.Name),
new XElement("phone", c.Phone),
new XElement("postal", c.Postal)
)
)
).ToArray()
)
);
Linq2sql will retrieve the data in a single call to the db, and the processing of the XML will be done at the business server. This splits the load better, since you don't have the sql server doing all the job.
Have you tried DataSet.WriteXml()?
You could have this be the output of a web service call.
Sql Server 2005 and above has a "FOR XML AUTO" command that will convert your recordset to XML for you. Then you just have to return a string from your ASHX.
Beginning with SQL Server 2000, you can return query results as XML. For absolute control of them, use the "FOR XML EXPLICIT" command. You can use any format you desire that way.
http://msdn.microsoft.com/en-us/library/ms189068.aspx
It's as easy as writing your result to the raw output then. For added points, you can return the result set to a XPathDocument, pass it through an XSL transformation, and send the results out in any format you choose (HTML vs XML at the click of a button perhaps).
you can obtained that to a datatable and then call myTable.WriteXML()
if you are populating classes with the your database results then add the serializable attribute to the header your classes, and use the XMLSerializer
Converting an automatically generated format into a specified one is a job for xslt. Just find a way to run the output from the tool through an xslt filter.
Oracle has a great product for doing exactly this job - the oracle XDK. But it's a java thing, not ASP as far as I know.
For an example, this XHTML
http://www.anbg.gov.au/abrs/online-resources/flora/stddisplay.xsql?pnid=2524
is generated automatically from this XML, which is generated by oracle
http://www.anbg.gov.au/abrs/online-resources/flora/stddisplay.xsql?pnid=2524&xml-stylesheet=none
Of course, you are not after XHTML, but some other XML format. But XSLT will do the job.

Resources