I'm new to xquery and is trying to read different references on using the tool. I've been trying to play around testing and trying to generate some xml format messages but this one puzzles me. Here's my xQuery code:
Sample XQuery
declare variable $requestBody as element() external;
declare function VerifyOrderDetailTransformation($requestBody as element())
as element() {
<msg>
<header>
<headtitle>This is the title</headtitle>
</header>
<dbody>
{GenerateEquipmentListNodes($requestBody)}
</dbody>
</msg>
};
declare function GenerateEquipmentListNodes($requestBody as element())
as element()* {
let $titleList := (
for $e in $requestBody//bookstore//book
let $dTitle := $e/title/text()
return
<theTitle>{$dTitle}</theTitle>
)
return
<dTitleList>
{$titleList}
</dTitleList>
};
VerifyOrderDetailTransformation($requestBody)
Sample XML
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
And here's the output generated by running xQuery on the XML:
Current output
<msg>
<head>
<title>This is the title</title>
</head>
<body>
<dTitleList/>
</body>
</msg>
Expected Output
<msg>
<head>
<title>This is the title</title>
</head>
<body>
<dTitleList>
<theTitle>Everyday Italian</theTitle>
<theTitle>Harry Potter</theTitle>
<theTitle>XQuery Kick Start</theTitle>
<theTitle>Learning XML</theTitle>
<dTitleList/>
</body>
</msg>
My question is, what could I have probably missed?
There is some problem with your input: You're querying this XML:
<bookstore>
<book>
<!-- snip -->
</book>
<!-- snip -->
</bookstore>
The first part of your XPath query, namely $queryBody//bookstore, looks for all descendant elements which have an element <bookstore/> below - what return an empty result. $queryBody//bookstore won't do either, as the context already is on the <bookstore/> element.
For this reason, ommit //bookstore, so your this should be $queryBody//book.
Use this function with the changed XPath in it:
declare function local:GenerateEquipmentListNodes($requestBody as element())
as element()* {
let $titleList := (
for $e in $requestBody//book
let $dTitle := $e/title/text()
return
<theTitle>{$dTitle}</theTitle>
)
return
<dTitleList>
{$titleList}
</dTitleList>
};
One more remark: You should put your own functions into local: function namespace or define your own one. Using the default namespace is discouraged and not compatible with all processors. I changed it to the local:-namespace.
Related
Team, I need your help /expertise to retrieve node value by traversing an xml response. I would like to use this an integration middleware.
Input file sample:
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xml:base="https://api12preview.sapsf.eu:443/odata/v2/">
<title type="text">PerEmail</title>
<id>https://api12preview.sapsf.eu:443/odata/v2/PerEmail</id>
<updated>2022-11-09T13:58:27Z</updated>
<link href="PerEmail" rel="self" title="PerEmail"/>
<entry>
<id>https://api12preview.sapsf.eu:443/odata/v2/PerEmail(emailType='54139',personIdExternal='GI00152188')</id>
<title type="text"/>
<updated>2022-11-09T13:58:27Z</updated>
<author>
<name/>
</author>
<link href="PerEmail(emailType='54139',personIdExternal='GI00152188')"
rel="edit"
title="PerEmail"/>
<category scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
term="SFOData.PerEmail"/>
<content type="application/xml">
< properties>
<d:personIdExternal>GI00152188</d:personIdExternal>
<d:emailAddress>someone#test_boehringer.com</d:emailAddress>
</m:properties>
</content>
</entry>
<entry>
<id>https://api12preview.sapsf.eu:443/odata/v2/PerEmail(emailType='54139',personIdExternal='GI00453224')</id>
<title type="text"/>
<updated>2022-11-09T13:58:27Z</updated>
<author>
<name/>
</author>
<link href="PerEmail(emailType='54139',personIdExternal='GI00453224')"
rel="edit"
title="PerEmail"/>
<category scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
term="SFOData.PerEmail"/>
<content type="application/xml">
<m:properties>
<d:personIdExternal>GI00453224</d:personIdExternal>
<d:emailAddress>someone#test_boehringer.com</d:emailAddress>
</m:properties>
</content>
</entry>
<link href="https://api12preview.sapsf.eu:443/odata/v2/PerEmail?$select=emailAddress,personIdExternal&$filter=emailType%20eq%2054139&$skiptoken=eyJzdGFydFJvdyI6MTAwMCwiZW5kUm93IjoyMDAwfQ=="
rel="next"/>
</feed>
Out of this response or xml Xquery should run through all 'entry' node and pick values of node 'personIdExternal' and I'm expecting result like this
<element>
<personIdExternal>GI00152188</personIdExternal>
<personIdExternal>GI00453224</personIdExternal>
</element>
I have tried something below code earlier but it's not working here, and I suspect this is due to namespace in the source xml. My knowledge is limited in XQuery - Please help
{let $input:= /entry
for $i in $input/properties
return
<element>
<personIdExternal>{i/personIdExternal/text()}</personIdExternal>
</element>}
/entry doesn't select anything because the entry elements aren't at the top level, and they're in a namespace.
$input/properties is wrong because the properties element isn't a child of entry and it's in a namespace.
i doesn't select anything, it should be $i
personIdExternal doesn't select anything because it's in a namespace.
You just need
<element>{//*:personIdExternal}</element>
I would like to extract only the child node "body" from a given XML file and then save it again as an XML file. How can I achieve this?
The XML file looks like this:
<books>
<book date="2019-01-04" xml:lang="de">
<title>...</title>
<body>...</body>
<copyright>...</copyright>
<categories>
<category>
<topic d="0">...</topic>
<topic d="1" label="True">...</topic>
</category>
</categories>
<authors>...</authors>
<published>...</published>
<isbn>...</isbn>
<url>...</url>
</book>
...
</books>
I already tried the function saveXML but I don't know how I can choose only one node.
I expect a XML file like this:
<books>
<book date="2019-01-04" xml:lang="de">
<body>...</body>
</book>
...
</books>
How to do node replacement in MarkLogic for a particular attribute? For example like below:
<chapters>
<title id="primary">first primary content</title>
<title id="primary">second primary content</title>
<title id="secondary">this is amy middle content</title>
<title id="terciary">this is amy last content</title>
</chapters>
I want like below:
<chapters>
<title id="primary">third primary content</title>
<title id="secondary">this is amy middle content</title>
<title id="terciary">this is amy last content</title>
</chapters>
I mean suppose A.xml file stored in MarkLogic database server that contain data like bleow:
<chaptermetadata>
<chapters>
<title id="primary">first content</title>
<title id="primary">second content</title>
<title id="secondary">This is middle content</title>
<title id="terciary">This is last content</title>
</chapters>
<chapters>
<title id="primary">fouth content</title>
<title id="primary">fifth content</title>
<title id="primary">sixth content</title>
<title id="secondary">This is new content</title>
<title id="terciary">This is old content</title>
</chapters>
<chaptermetadata>
Now, I want to replace a node in all the element title which contain attribute #id='primary' in all chapter like below:
<chaptermetadata>
<chapters>
<title id="primary">common content</title>
<title id="secondary">This is middle content</title>
<title id="terciary">This is last content</title>
</chapters>
<chapters>
<title id="primary">common content</title>
<title id="secondary">This is new content</title>
<title id="terciary">This is old content</title>
</chapters>
<chaptermetadata>
If you are just getting started with XQuery and MarkLogic, http://developer.marklogic.com/learn/technical-overview and http://developer.marklogic.com/learn may help.
The best way to modify elements and attributes depends on the context, which you haven't supplied. I suppose the first question is "how do I select nodes by attribute?" A simple bit of XPath does that. For all chapters in the database:
/chapters/title[#id eq $id]
...or relative to a previously selected sequence of element(chapter)*
$chapters/title[#id eq $id]
If this is a database document, you could take it from there with the http://docs.marklogic.com/xdmp:node-replace and http://docs.marklogic.com/xdmp:node-delete functions. If the nodes are only in memory, see http://docs.marklogic.com/guide/app-dev/typeswitch for guidance and examples on using an XQuery typeswitch or XSLT. At http://developer.marklogic.com/blog/tired-of-typeswitch there are more examples and comparison of typeswitch and XSLT.
Based upon the examples you provided, it appears that you want to replace the text() for the first title element that has #id='primary', and remove the othertitleelements with#id='primary'`.
The following will achieve that, using xdmp:node-replace() and xdmp:node-delete() methods.
for $primary-title in doc("A.xml")/chaptermetadata/chapters/title[#id='primary']
return
if ($primary-title/preceding-sibling::title[#id='primary'])
then xdmp:node-delete($primary-title)
else xdmp:node-replace($primary-title/text(), text{"common content"})
i have here an xml file from my local drive.
my question is how can I convert this xml file to datatable?
can anypone help me? thanks in advance.
string filePath = "../../Sample.xml";
DataTable dt = new DataTable("Sample");
//columns
dt.Columns.Add("Column1", typeof(int));
dt.Columns.Add("Column2", typeof(string));
dt.ReadXml(filePath);
GridView1.DataSource = dt;
GridView1.DataBind();
what if the XML has subitems like this one.
<table1>
<Sample>
<Sample_1 Code="1" Desc="xxx">
<Detail>
<Detail Desc1="01" Desc2="aaa" Desc3="+++" />
<Detail Desc1="02" Desc2="bbb" Desc3="--" />
<Detail Desc1="03" Desc2="ccc" Desc3=",,," />
</Details>
<Sample>
<Sample>
<Sample_2 Code="2" Desc="yyy">
<Details>
<Detail Desc1="01" Desc2="aaa" Desc3="+++" />
<Detail Desc1="02" Desc2="bbb" Desc3="--" />
<Detail Desc1="03" Desc2="ccc" Desc3=",,," />
</Details>
<Sample>
</table1>
The current version of jqGrid has supportfor this. See this example
http://www.ok-soft-gmbh.com/jqGrid/XmlWithAttributes.htm
UPDATE
Please see below the code to showing an XML file into jsGrid
HTML
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/themes/redmond/jquery-ui.css" />
<link rel="stylesheet" type="text/css" href="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.3.1/css/ui.jqgrid.css" />
<style type="text/css">
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.3.1/js/i18n/grid.locale-en.js"></script>
<script type="text/javascript">
$.jgrid.no_legacy_api = true;
$.jgrid.useJSON = true;
</script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.3.1/js/jquery.jqGrid.src.js"></script>
<script type="text/javascript">
//<![CDATA[
/*global $ */
/*jslint browser: true, plusplus: true */
$(function () {
'use strict';
$("#ourunittb").jqGrid({
url: 'Sample.xml',
datatype: "xml",
height: 'auto',
colModel: [
{ name: 'Author', width: 150,
xmlmap: function (obj) {
return $(obj).find("author").first().text();
}
},
{ name: 'Title', width: 300, xmlmap: function (obj) {
return $(obj).find("title").first().text();
}
}
],
xmlReader: {
root: "catalog",
row: "book",
repeatitems: false
},
loadonce: true,
rowNum: 1000
});
});
//]]>
</script>
</head>
<body>
<table id="ourunittb"><tr><td/></tr></table>
</body>
</html>
SAMPLE XML FILE
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book id="bk103">
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
<book id="bk104">
<author>Corets, Eva</author>
<title>Oberon's Legacy</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2001-03-10</publish_date>
<description>In post-apocalypse England, the mysterious
agent known only as Oberon helps to create a new life
for the inhabitants of London. Sequel to Maeve
Ascendant.</description>
</book>
<book id="bk105">
<author>Corets, Eva</author>
<title>The Sundered Grail</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2001-09-10</publish_date>
<description>The two daughters of Maeve, half-sisters,
battle one another for control of England. Sequel to
Oberon's Legacy.</description>
</book>
<book id="bk106">
<author>Randall, Cynthia</author>
<title>Lover Birds</title>
<genre>Romance</genre>
<price>4.95</price>
<publish_date>2000-09-02</publish_date>
<description>When Carla meets Paul at an ornithology
conference, tempers fly as feathers get ruffled.</description>
</book>
<book id="bk107">
<author>Thurman, Paula</author>
<title>Splish Splash</title>
<genre>Romance</genre>
<price>4.95</price>
<publish_date>2000-11-02</publish_date>
<description>A deep sea diver finds true love twenty
thousand leagues beneath the sea.</description>
</book>
<book id="bk108">
<author>Knorr, Stefan</author>
<title>Creepy Crawlies</title>
<genre>Horror</genre>
<price>4.95</price>
<publish_date>2000-12-06</publish_date>
<description>An anthology of horror stories about roaches,
centipedes, scorpions and other insects.</description>
</book>
<book id="bk109">
<author>Kress, Peter</author>
<title>Paradox Lost</title>
<genre>Science Fiction</genre>
<price>6.95</price>
<publish_date>2000-11-02</publish_date>
<description>After an inadvertant trip through a Heisenberg
Uncertainty Device, James Salway discovers the problems
of being quantum.</description>
</book>
<book id="bk110">
<author>O'Brien, Tim</author>
<title>Microsoft .NET: The Programming Bible</title>
<genre>Computer</genre>
<price>36.95</price>
<publish_date>2000-12-09</publish_date>
<description>Microsoft's .NET initiative is explored in
detail in this deep programmer's reference.</description>
</book>
<book id="bk111">
<author>O'Brien, Tim</author>
<title>MSXML3: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>36.95</price>
<publish_date>2000-12-01</publish_date>
<description>The Microsoft MSXML3 parser is covered in
detail, with attention to XML DOM interfaces, XSLT processing,
SAX and more.</description>
</book>
<book id="bk112">
<author>Galos, Mike</author>
<title>Visual Studio 7: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>49.95</price>
<publish_date>2001-04-16</publish_date>
<description>Microsoft Visual Studio 7 is explored in depth,
looking at how Visual Basic, Visual C++, C#, and ASP+ are
integrated into a comprehensive development
environment.</description>
</book>
</catalog>
OUTPUT
Input document:
<entry xmlns="http://www.w3.org/2005/Atom">
<id>urn:uuid:1234</id>
<updated>2012-01-20T11:30:11-05:00</updated>
<published>2011-12-29T15:44:11-05:00</published>
<link href="?id=urn:uuid:1234" rel="edit" type="application/atom+xml"/>
<title>Title</title>
<category scheme="http://uri/categories" term="category"/>
<fake:fake xmlns:fake="http://fake/" attr="val"/>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Blah</p>
</div>
</content>
</entry>
<!-- more entries -->
I want the output to be exactly the same, but with non-Atom elements like <fake:fake xmlns:fake="http://fake/" attr="val"/> stripped out. This is what I have, which doesn't work at all, just giving me the same input back:
declare namespace atom = "http://www.w3.org/2005/Atom";
<feed>
<title>All Posts</title>
{
for $e in collection('/db/entries')/atom:entry
return
if
(namespace-uri($e) = "http://www.w3.org/2005/Atom")
then
$e
else
''
}
</feed>
What am I doing wrong?
You can try the following query on try.zorba-xquery.com:
let $entry := <entry xmlns="http://www.w3.org/2005/Atom">
<id>urn:uuid:1234</id>
<updated>2012-01-20T11:30:11-05:00</updated>
<published>2011-12-29T15:44:11-05:00</published>
<link href="?id=urn:uuid:1234" rel="edit" type="application/atom+xml"/>
<title>Title</title>
<category scheme="http://uri/categories" term="category"/>
<fake:fake xmlns:fake="http://fake/" attr="val"/>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Blah</p>
</div>
</content>
</entry>
return {
delete nodes $entry//*[not(namespace-uri(.) = "http://www.w3.org/2005/Atom")];
$entry
}
The following version is more portable:
let $entry := <entry xmlns="http://www.w3.org/2005/Atom">
<id>urn:uuid:1234</id>
<updated>2012-01-20T11:30:11-05:00</updated>
<published>2011-12-29T15:44:11-05:00</published>
<link href="?id=urn:uuid:1234" rel="edit" type="application/atom+xml"/>
<title>Title</title>
<category scheme="http://uri/categories" term="category"/>
<fake:fake xmlns:fake="http://fake/" attr="val"/>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Blah</p>
</div>
</content>
</entry>
return
copy $new-entry := $entry
modify (delete nodes $new-entry//*[not(namespace-uri(.) = "http://www.w3.org/2005/Atom")])
return $new-entry
Sort of a round-about way of doing it but this ended up working:
declare default element namespace "http://www.w3.org/2005/Atom";
<feed>
<title>All Posts</title>
{
for $entry in collection('/db/entries')/entry
return
element{node-name($entry)}{
$entry/#*,
for $child in $entry//*[namespace-uri(.) = "http://www.w3.org/2005/Atom"]
return $child
}
}
</feed>
Waiting for the time limit to expire and then I'll accept it as an answer.