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"})
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>
Suppose I have the following XML:
library(xml2)
x = xml_children(read_xml('<?xml version="1.0" encoding="UTF-8"?>
<items>
<item type="greeting" id="9273938">
<link type="1" id="139" value="Hi"/>
<link type="1" id="142" value="Hello"/>
<link type="1" id="130" value="Ahoy"/>
</item>
<item type="greeting" id="9225694">
<link type="1" id="138" value="Bye"/>
<link type="1" id="131" value="Adios"/>
</item>
</items>'))
I can loop over it to access the <link> nodes in the individual <item> nodes.
lapply(x, xml_find_all, xpath = "link")
This produces a list of separate nodesets, which allows me to know which collection of "links" belongs to which "item". But looping over a longish nodeset (say thousands of <item> nodes) can be slow.
In contrast the below is almost instant (and I think closer to the spirit of how xml2 should be used) but I no longer know which item the links came from. They appear to all be siblings:
xml_find_all(x, xpath = "link")
Question: How to extract the <link> nodes without losing information about the <item> they came from, avoiding the lapply solution above?
With each link node, you can get the information about the parent item by /parent::item:
library(xml2)
x <- read_xml('<?xml version="1.0" encoding="UTF-8"?>
<items>
<item type="greeting" id="9273938">
<link type="1" id="139" value="Hi"/>
<link type="1" id="142" value="Hello"/>
<link type="1" id="130" value="Ahoy"/>
</item>
<item type="greeting" id="9225694">
<link type="1" id="138" value="Bye"/>
<link type="1" id="131" value="Adios"/>
</item>
</items>')
links <- x %>% xml_find_all("//link")
data.frame(
item_id = links %>% xml_find_first("./parent::item") %>% xml_attr("id"), # notice the dot refers to the current link node
link_id = links %>% xml_attr("id"),
value = links %>% xml_attr("value")
)
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.
This is a fairly straightforward question for such odd behaviour, but that is exactly what my app is doing on the Playbook. I open the app the first time and it runs perfectly. I close the app, and then open it again and it hangs/freezes after the first action I perform with it. I then close the app, it seems to reset itself, and then opens and runs perfectly the next time.
I am using the latest WebWorks and am debugging on the PB with a debug token. My previous app (written/tested on pre OS2.0) worked, and continues to work, just fine.
I am pleased to post code if you would like, but it may be a waste of space. In an effort to root out the problem, I wrote a quick Hello World app that writes one item to an HTML5 database on the playbook (my main app also uses WebDB), and that app, as simple as it is, has exactly the same behavior. All my apps function fine in Chrome.
If anyone has any thoughts about what could be causing this behaviour, please post a reply.
HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript" src="helloworld.js"></script>
</head>
<body>
<input type="text" id="testDBInput"/>
<button type="button" onclick="testDB()">go</button>
</body>
</html>
JavaScript Document:
var taskdb=openDatabase ("helloworldDB", "1.0", "test database", 10*1024*1024);
taskdb.transaction(function(tx)
{
tx.executeSql("CREATE TABLE IF NOT EXISTS maintable (id integer primary key autoincrement, nametitle TEXT)");
});
function testDB()
{
var testTitle=document.getElementById("testDBInput").value;
taskdb.transaction(function(tx)
{
tx.executeSql("INSERT INTO maintable (nametitle) VALUES (?)", [testTitle], function (tx, results)
{
});
});
}
blackberry-tablet.xml:
<?xml version="1.0" encoding="utf-8"?>
<qnx>
<icon>
<image></image>
</icon>
<author>***edited for privacy***</author>
<authorId>***edited for privacy***</authorId>
<platformVersion>1.0.0.0</platformVersion>
</qnx>
config.xml:
<?xml version="1.0" encoding="utf-8"?>
<widget xmlns=" http://www.w3.org/ns/widgets"
xmlns:rim="http://www.blackberry.com/ns/widgets"
version="1.0.0.0">
<name>Tester</name>
<description>
PB Tester
</description>
<rim:orientation mode="landscape"/>
<rim:loadingScreen onFirstLaunch="true" >
</rim:loadingScreen>
<author>***edited for privacy***</author>
<icon src="bdicon.png"/>
<content src="index.html"/>
<feature id="blackberry.app" required="true" version="1.0.0.0"/>
<feature id="blackberry.ui.dialog" required="true" version="1.0.0.0"/>
</widget>
It sounds like the javascript crashed when the appli hangs. testDB() has few lines, you can insert alert() to see which line is not reached
How to describe comments tree with Atom/RSS?
There's a draft standard to extend Atom with threaded discussions, but that's no longer active. This is a feed with comments:
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:thr="http://purl.org/syndication/thread/1.0">
<id>http://www.example.org/myfeed</id>
<title>My Example Feed</title>
<updated>2005-07-28T12:00:00Z</updated>
<link href="http://www.example.org/myfeed" />
<author><name>James</name></author>
<entry>
<id>tag:example.org,2005:1</id>
<title>My original entry</title>
<updated>2006-03-01T12:12:12Z</updated>
<link
type="application/xhtml+xml"
href="http://www.example.org/entries/1" />
<summary>This is my original entry</summary>
</entry>
<entry>
<id>tag:example.org,2005:1,1</id>
<title>A response to the original</title>
<updated>2006-03-01T12:12:12Z</updated>
<link href="http://www.example.org/entries/1/1" />
<thr:in-reply-to
ref="tag:example.org,2005:1"
type="application/xhtml+xml"
href="http://www.example.org/entries/1"/>
<summary>This is a response to the original entry</summary>
</entry>
</feed>
You can use html in RSS but < and > must be present as < and >
<description>
...
<!-- comments -->
<ul>
<li>comment1</li>
<li>comment2</li>
<li>comment3</li>
<li>comment4</li>
<ul>
</description>