I have an xml like
<NS5:CAIAssembly>
<NS5:CAIComponent >
<NS5:CAICode>033144</NS5:CAICode>
<NS5:Quantity>1</NS5:Quantity>
</NS5:CAIComponent>
<NS5:CAIComponent >
<NS5:CAICode>048429</NS5:CAICode>
<NS5:Quantity>1</NS5:Quantity>
</NS5:CAIComponent>
<NS5:CAIComponent >
<NS5:CAICode>073528</NS5:CAICode>
<NS5:Quantity>1</NS5:Quantity>
</NS5:CAIComponent>
<NS5:CAIComponent >
<NS5:CAICode>563781</NS5:CAICode>
<NS5:Quantity>1</NS5:Quantity>
</NS5:CAIComponent>
</NS5:CAIAssembly>
I have written like to get the values of
SET OutputRoot.XMLNSC.root.row[rowCnt].Kit_info.components.productCd = COALESCE(FIELDVALUE(orgObj.*:ListOfCAD.*:CAD.*:CADAssembly.*:CADComponent.*:CAICode[]),'0')||'_'||COALESCE(FIELDVALUE(orgObj.*:ListOfCAD.*:CAD.*:CADAssembly.*:CADComponent.*:CCIDCode[]),'0');
SET OutputRoot.XMLNSC.root.row[rowCnt].Kit_info.components.quantity = FIELDVALUE(orgObj.*:CAIAssembly.*:CAIComponent.*:Quantity[]);
the above code give me result like only one
<components>
<productCd >033144_5423</productCd >
<quantity>1</quantity>
</components
>
How can I iterate the values to get all like
I have tried the While loop but its not working
<components>
<productCd >033144_5423</productCd >
<quantity>1</quantity>
</components>
<components>
<productCd >048429_5423</productCd >
<quantity>1</quantity>
</components>
<components>
<productCd >073528_5423</productCd >
<quantity>1</quantity>
</components>
<components>
<productCd >563781_5423</productCd >
<quantity>1</quantity>
</components>
Thanks all.
This is very simple to achieve. Try below code:
DECLARE inputRef REFERENCE TO InputRoot.XMLNSC.NS5:CAIAssembly;
DECLARE Ref_CAIComponent REFERENCE TO inputRef.NS5:CAIComponent[1];
--Now run the below loop
WHILE LASTMOVE(Ref_CAIComponent) DO
CREATE FIELD OutputRoot.XMLNSC.components[index];
DECLARE outRef REFERENCE TO OutputRoot.XMLNSC.components[index];
SET index=index+1;
SET outRef.productCd=Ref_CAIComponent.NS5:CAICode;
SET outRef.quantity=Ref_CAIComponent.NS5:Quantity;
MOVE Ref_CAIComponent NEXTSIBLING REPEAT NAME;
END WHILE;
P.S. It's good practice to struggle and find solutions at your own, rather than searching for spoon feeding.
Related
this is the xml file:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:putResponse
xmlns:ns1="urn:DmsManagerClient">
<result xsi:type="xsd:string">
<?xml version="1.0" encoding="ISO-8859-1"?>
<MESSAGE ID="11c73b9e-687c-4300-baba-b743c26f7c83" TYPE="CUSDMS">
<DELIVERY>
<FROM>
<SENDER>0072000</SENDER>
<SERVICE>eService</SERVICE>
<DATE>2019-03-08T12:27:25</DATE>
</FROM>
<TO>
<DEALER DEALERCODE="0072000" MARKETCODE="1000"/>
</TO>
</DELIVERY>
<CONTENT>
<dms:ComplexResponse ErrorCode="430" ErrorDescription="null : PrivacyUE Mancante" Return="false"
xmlns:dms="http://dmsmanagerservice">
<dms:Element Name="DMSVERSION">2.7</dms:Element>
</dms:ComplexResponse>
</CONTENT>
</MESSAGE>
</result>
</ns1:putResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I am coding with Ruby and I used Nokogiri and the method xpath to extrapole the "CONTENT" of the file
this is the code:
def extrapolate_error(xml)
doc = Nokogiri::XML(File.open(xml))
doc.xpath('//CONTENT')
end
and this is the result:
[#<Nokogiri::XML::Element:0x1c5ba78 name="CONTENT" children=[
#<Nokogiri::XML::Text:0x1c5b940 "\n">,
#<Nokogiri::XML::Element:0x1c5b8bc name="ComplexResponse" namespace=#<Nokogiri::XML::Namespace:0x1c5b88c prefix="dms" href="http://dmsmanagerservice">
attributes=[
#<Nokogiri::XML::Attr:0x1c5b874 name="ErrorCode" value="430">,
#<Nokogiri::XML::Attr:0x1c5b868 name="ErrorDescription" value="null : PrivacyUE Mancante">,
#<Nokogiri::XML::Attr:0x1c5b85c name="Return" value="false">]
children=[#<Nokogiri::XML::Text:0x1c5b118 "\n">,
#<Nokogiri::XML::Element:0x1c5b094 name="Element" namespace=#<Nokogiri::XML::Namespace:0x1c5b88c prefix="dms" href="http://dmsmanagerservice">
attributes=[#<Nokogiri::XML::Attr:0x1c5b058 name="Name" value="DMSVERSION">]
children=[#<Nokogiri::XML::Text:0x1c5abe4 "2.7">]>,
#<Nokogiri::XML::Text:0x1c5aaac "\n">]>,
#<Nokogiri::XML::Text:0x1c5a974 "\n">]>]
Now I need to enter in it and select some attributes.
In the specific I need this:
name="ErrorCode" value="430"
name="ErrorDescription" value="null : PrivacyUE Mancante"
I do not know how to procceed. Can you help me?
The following should work for you assuming the dms namespace is always the same
doc.xpath('//CONTENT/dms:ComplexResponse', dms: 'http://dmsmanagerservice')
.xpath('#ErrorCode | #ErrorDescription')
.each_with_object({}) do |e,obj|
obj[e.name] = e.text
end
#=> {"ErrorCode"=>"430", "ErrorDescription"=>"null : PrivacyUE Mancante"}
You already understand how you got to //CONTENT so from there we use dms:ComplexResponse to navigate deeper but since this is namespaced we have to provide the namespace reference e.g. dms: 'http://dmsmanagerservice'.
Then we select the attributes we are interested in #ErrorCode and #ErrorDescription.
In XPath the pipe | means UNION (think AND) so we want to select both.
Then we are just building a Hash using the name as the key and the text as the value.
XPath Cheatsheet - Useful resource if you need additional reference
Update
You asked about conditionals so this is what I would propose
ndoc = Nokogiri::XML(doc)
namespaces = ndoc.collect_namespaces
response = ndoc.xpath("//CONTENT/dms:ComplexResponse", namespaces)
if response.xpath("self::node()[#ErrorCode != '' and #ErrorDescription != '']").any?
response.xpath("#ErrorCode | #ErrorDescription")
.each_with_object({}) do |e,obj|
obj[e.name] = e.text
end
else
response.xpath('dms:Element/#Name | dms:Element/text()',namespaces)
.each_slice(2)
.map {|s| s.map(&:text)}.to_h
end
This checks to see if there is an ErrorCode and and ErrorDescription if so then Hash as originally proposed. If Not then it returns all the dms:Elements as a Hash so {"DMSVERSION"=>"2.7"} in this case Functional Example
I want to read the data from passage_para tag, after passage_para I have 2 spaces before the expression tag and after the expression tag I have one more space, etc. When I use extract function to get the passage_para tag from the XMLTYPE column it is eliminating all the spaces.
<?xml version="1.0" encoding="UTF-8"?> <item> <information number="sdjsadh" > <response_direction delivery_mode="xcs"> <dparagraph>test</dparagraph> </response_direction> </information> <i_content> <stimulus_reference> <passage> <prose style="1"> <passage_para> <expression> <math xmlns="Math" xmlns:xlink="xlink" display="inline" overflow="scroll"> <mr> <mi>z</mi> <mo>></mo> <mn>0</mn> </mr> </math> </expression> </passage_para> </prose> </passage> </stimulus_reference> </i_content> </item>
which I don't want because it is taking out the spaces. The desired output I need is " z > 0 ".
Note: Between the passage_para tag the child nodes may change, they are not going to be the same.
I have a folder structure like this:
wsdl/v1,----,v11
I need to copy all of its files to a new folder called "latestVersion" and I need to maintain the copying order from v1 to v11. So to do that, I need to sort the directories by name while copying. My code is like this:
<copy todir="${srcdist.layout.dir}/etc/wsdl/latestVersion" flatten="true" overwrite="true" verbose="true">
<sort>
<fileset dir="../../sdk/etc/wsdl">
<include name="**/*.wsdl"/>
</fileset>
</sort>
</copy>
I would like the copying to start from v1 and end in v11. However, it copies like this:
v1,v10,v11,v2,v3,v4,v5,v6,v7,v8,v9
How, instead, do I get Ant to copy like:
v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11
Ant is sorting correctly, since v10 comes before v2 lexicographically (the sorting comparator compares characters one by one).
In order to have v2 before v11 you have to write a custom comparator (the list of built-in comparators in the documentation is not enough). In other words, you have to write a class that implements the org.apache.tools.ant.types.resources.comparators.ResourceComparator class, add your class to the classpath and declare it as a typedef in your Ant script:
<typedef name="my_custom_sort" classname="com.example.MyCustomResourceComparator" />
You can use JavaScript embedded in an Ant script to numerically sort the directory names.
Then, you can use <for> task from the third-party Ant-Contrib library to copy from the sorted directories one at a time:
<dirset id="wsdl.dirs" dir="../../sdk/etc/wsdl" includes="v*"/>
<script language="javascript">
<![CDATA[
var dirSet = project.getReference( "wsdl.dirs" );
var ds = dirSet.getDirectoryScanner( project );
var includes = ds.getIncludedDirectories();
var versions = [];
for ( var i = 0; i < includes.length; i++ ) {
var dirname = includes[i]
// chop off the "v" from the front
var dirVersion = dirname.substr(1);
versions.push( dirVersion );
}
versionsSorted = versions.sort(function (a, b) {
return a - b;
});
// the "list" of <for> takes a comma-delimited string
project.setProperty( "versions", versionsSorted.join( ',' ) );
]]>
</script>
<echo>sorted versions: ${versions}</echo>
<for list="${versions}" param="version">
<sequential>
<copy todir="${srcdist.layout.dir}/etc/wsdl/latestVersion">
<fileset dir="../../sdk/etc/wsdl/v#{version}" includes="**/*.wsdl"/>
</copy>
</sequential>
</for>
I have a XML file which contains multiple XML nodes. I would like to separate two XML notes and store them in separate variables. How would I write this functionality with XQuery? I have added my XML file below. Inside the XML file I have a division root element, Dive and top-song are two child elements. Now I want to read the Dive XML content in one variable and top-song content in another variable. Can any one please help me to sort out this issue?
<?xml version="1.0" encoding="UTF-8"?>
<division>
<Dive ID="2"><!-- I want this node in one variable -->
<DiverFName>Joe</DiverFName>
<DiverLName>Diver</DiverLName>
<Number>2</Number>
<Divedate>1998-03-30</Divedate>
<Country ID="1">Bahamas</Country>
<City ID="2">Freeport</City>
<Place ID="2">
<Site>South Pass</Site>
<Lat>24.865062</Lat>
<Lon>-77.871094</Lon>
</Place>
<Divetime>36.00</Divetime>
<Depth Scale="METRIC">5.48</Depth>
<Buddy IDs="2" Names="Tim Diver" />
<Comments>Great dive, saw 5 Caribbean Reef Sharks. Performed compass navigation skills for Scuba Diver certification.</Comments>
<Water>Salt</Water>
<Entry>Boat</Entry>
<Divetype>Research</Divetype>
<Tanktype>Alu</Tanktype>
<Tanksize>11.43</Tanksize>
<PresS>179.26</PresS>
<PresE>82.73</PresE>
<Gas>Air</Gas>
<Weather>Clear</Weather>
<UWCurrent>Medium Current</UWCurrent>
<MarineLife>
<Animal>
<Type>Nurse Shark</Type>
<Abundance>1</Abundance>
<Size>3 ft</Size>
<Description>Dormant on the bottom, not swimming.</Description>
<Image>
<Filename></Filename>
<Path></Path>
<Caption></Caption>
</Image>
</Animal>
<Animal>
<Type>Blue Tang Surgeonfish</Type>
<Abundance>25+</Abundance>
<Size>4 in</Size>
<Description>Blue with white "scalpel" near base </descreption>
<Image>
<Filename></Filename>
<Path></Path>
<Caption></Caption>
</Image>
</Animal>
</MarineLife>
</Dive>
<top-song><!-- I want this node in another variable -->
<title >Try Again</title>
<artist >Aaliyah</artist>
<weeks last="2008-06-17">
<week>2008-06-17</week>
</weeks>
<album> The
Album</album>
<released>February 29, 20008</released>
<formats>
<format>CD</format>
<format>12 single</format>
</formats>
<recorded>january2012</recorded>
<genres>
<genre>R&B</genre>
</genres>
<lengths>
<length>4:04</length>
</lengths>
<label>Blackground</label>
<writers>
<writer></writer>
<writer></writer>
</writers>
<producers>
<producer></producer>
</producers>
<descr>
<p>hai hello</p>
</descr>
</top-song>
</division>
It's not clear what you're trying to accomplish on a high level, but you can select those elements with some simple XQuery/Xpath:
let $dive := doc('mydoc.xml')/division/Dive
let $top-song := doc('mydoc.xml')/division/top-song
However, just looking at the document it's clear that these two elements are in totally unrelated schemas, and as a general recommendation for MarkLogic, they should probably each be separated before ingestion and inserted as separate documents.
I'm trying to get reviewers who review one or more books published after 2010.
for $r in doc("review.xml")//Reviews//Review,
$b in doc("book.xml")//Books//Book
where $b/Title = $r/BookTitle
and $b/Year > 2010
return {$r/Reviewer}
The following are both XML files.
review.xml:
<Reviews>
<Review>
<ReviewID>R1</ReviewID>
<BookTitle>B1</BookTitle>
<Reviewer>AAA</Reviewer>
</Review>
<Review>
<ReviewID>R2</ReviewID>
<BookTitle>B1</BookTitle>
<Reviewer>BBB</Reviewer>
</Review>
<Review>
<ReviewID>R3</ReviewID>
<BookTitle>B2</BookTitle>
<Reviewer>AAA</Reviewer>
</Review>
<Review>
<ReviewID>R4</ReviewID>
<BookTitle>B3</BookTitle>
<Reviewer>AAA</Reviewer>
</Review>
<Reviews>
book.xml:
<Books>
<Book>
<Title>B1</Title>
<Year>2005</Year>
</Book>
<Book>
<Title>B2</Title>
<Year>2011</Year>
</Book>
<Book>
<Title>B3</Title>
<Year>2012</Year>
</Book>
</Books>
I'll get two AAA by my xQuery code. I was wondering if I can get the distinct result, which means only one AAA. I've tried distinct-value() but don't know how to use it probably. Thanks for your reply!
----My Updated Solution with XML format for xQuery 1.0----
<root>
{
for $x in distinct-values
(
for $r in doc("review.xml")//Reviews//Review,
$b in doc("book.xml")//Books//Book
where $b/Title = $r/BookTitle
and $b/Year > 2010
return {$r/Reviewer}
)
return <reviewer>{$x}</reviewer>
}
</root>
To preserve nodes, you can use the "group by" clause and select the first item of a group sequence:
for $r in doc("review.xml")//Review,
$b in doc("book.xml")//Book
let $n := $r/Reviewer
where $b/Title = $r/BookTitle
and $b/Year > 2010
group by $n
return $r[1]/Reviewer
The following query will give you all distint reviewer names (note that the values are atomized, which means the element nodes are removed):
distinct-values(
for $r in doc("review.xml")//Reviews//Review,
$b in doc("book.xml")//Books//Book
where $b/Title = $r/BookTitle
and $b/Year > 2010
return $r/Reviewer
)