I'm new to Xquery. I have a requirement of rewriting the API response into custom xml format.
Input file format:
<root> <_1>
<dataType>
<name>XVar(Osmo [mOsmol/kg])</name>
<term>M185</term>
<type>XVar</type>
</dataType>
<values>305</values>
<values>335</values> </_1> <_2>
<dataType>
<name>XVar(DO (2) [%])</name>
<term>M199</term>
<type>XVar</type>
</dataType>
<values>12</values>
<values>33</values>
</_2> <_3>
<dataType>
<name>Maturity</name>
<type>Maturity</type>
</dataType>
<values>0</values>
<values>0.73600054</values>
</_3> </root>
Expected output:
<element> <XVar(Osmo [mOsmol/kg]> 305</XVar(Osmo [mOsmol/kg]>
<XVar(Osmo [mOsmol/kg]> 335</XVar(Osmo [mOsmol/kg]> <XVar(DO (2)[%])>
12</XVar(DO (2) [%])> <XVar(DO (2) [%])>33 </XVar(DO (2) [%])>
<Maturity>0</Maturity> <Maturity>0.73600054</Maturity> </element>
no of nodes (dataType -> name) will vary in each input file and also
Values will be dynamics .
currently using the below code.
let $input:= /root for $i in $input//values
return <element>
<name>{$i/../dataType/name/text()}</name> <values>{$i/text()} </values>
</element>
but all data are coming in and . my requirement is to
keep the node name as {$i/../dataType/name/text()} as values should
be {$i/text()} -
for the input file sample ideally there should be three different
nodes and its values.
Can any one help me on this?
Related
I have something like this in an input XML
<OrderText>
<text_type>0012</text_type>
<text_content>Text1</text_content>
</OrderText>
<OrderText>
<text_type>ZT03</text_type>
<text_content>Text2</text_content>
</OrderText>
The above data I need to map after concatenating as the below schema
<Order>
<Note>0012:Text1#ZT03:Text2</Note>
</Order>
Can anyone please help?
I'm going to assume that your input actually has a Root node, as otherwise it is not valid XML.
<Root>
<OrderText>
<text_type>0012</text_type>
<text_content>Text1</text_content>
</OrderText>
<OrderText>
<text_type>ZT03</text_type>
<text_content>Text2</text_content>
</OrderText>
</Root>
Then all you need is a map like this
With a String Concatenate functoid with
Input[0] = text_type
Input[1] = :
Input[2] = text_content
Input[3] = #
That goes into a Cumulative Concatenate
This will give you an output of
<Order>
<Note>0012:Text1#ZT03:Text2#</Note>
</Order>
Note: There is a extra # at the end, but you could use some more functoids to trim that off if needed.
You can use the Value-Mapping Flattening functoid in a map, then feed the result of each into a Concatenate functoid to generate the result string. The map can be executed on a port or in an orchestration.
This is the xml file.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<AtcoCode> System-Start-Date= 2018-05-16T12:35:48.6929328-04:00, " ", System-End-Date = 9999-12-31, " ", 150042010003</AtcoCode>
<NaptanCode>esxatgjd</NaptanCode>
<PlateCode>
</PlateCode>
<CleardownCode>
</CleardownCode>
<CommonName>Upper Park</CommonName>
<CommonNameLang>
</CommonNameLang>
<ShortCommonName>
</ShortCommonName>
<ShortCommonNameLang>
</ShortCommonNameLang>
<Landmark>Upper Park</Landmark>
<LandmarkLang>
</LandmarkLang>
<Street>High Road</Street>
<StreetLang>
</StreetLang>
<Crossing>
</Crossing>
<CrossingLang>
</CrossingLang>
<Indicator>adj</Indicator>
<IndicatorLang>
</IndicatorLang>
<Bearing>NE</Bearing>
<NptgLocalityCode>E0046286</NptgLocalityCode>
<LocalityName>Loughton</LocalityName>
<ParentLocalityName>
</ParentLocalityName>
<GrandParentLocalityName>
</GrandParentLocalityName>
<Town>Loughton</Town>
<TownLang>
</TownLang>
<Suburb>
</Suburb>
<SuburbLang>
</SuburbLang>
<LocalityCentre>1</LocalityCentre>
<GridType>U</GridType>
<Easting>541906</Easting>
<Northing>195737</Northing>
<Co-ordinates>51.64255,0.04944</Co-ordinates>
<StopType>BCT</StopType>
<BusStopType>MKD</BusStopType>
<TimingStatus>OTH</TimingStatus>
<DefaultWaitTime>
</DefaultWaitTime>
<Notes>
</Notes>
<NotesLang>
</NotesLang>
<AdministrativeAreaCode>080</AdministrativeAreaCode>
<CreationDateTime>2006-11-06T00:00:00</CreationDateTime>
<ModificationDateTime>2010-01-16T07:58:02</ModificationDateTime>
<RevisionNumber>5</RevisionNumber>
<Modification>rev</Modification>
<Status>act</Status>
</root>
How to achieve this?
Question: Create the path range index for the status element and fetch all the documents that has status del
after fetching all the documents, you need to create the new element called currentreservationnumber under RevisionNumber element.
The value of the currentrevisionnumber will be +1 to the RevisionNumber.
I think the warning about sequential numbers is related to system-wide unique numbers/ids (like Oracle sequence), so not a worry in this case?
If you only ever have one RevisionNumber, and you can find it without a path index, you can maybe get by with element-value query on the RevisionNumber since it's already indexed.
Given that you get the document somehow, it could be as simple as:
let $doc := fn:doc ('/foo.xml')
let $rev-node := $doc/root/RevisionNumber
return xdmp:node-insert-after ($rev-node, <currentreservationnumber>{$rev-node + 1}</currentreservationnumber>)
though remember to consider locking if you are doing a big query/update. And you might need to switch to node-replace if there is already a currentreservationnumber.
Background
I'm using a cts search in MarkLogic and it is not sorting by the passed sort option.
For example the following produces unsorted results
xdmp:document-insert("/test/test1",<test attrDate="2016-1-10"></test>);
xdmp:document-insert("/test/test2",<test attrDate="2015-1-10"></test>);
xdmp:document-insert("/test/test3",<test attrDate="2017-1-10"></test>);
cts:search(
xdmp:directory("/test/", "infinity")/test,
cts:true-query(),
(
cts:index-order(cts:element-attribute-reference(xs:QName("test"), xs:QName("attrDate")), ("ascending"))
)
);
This returns the following:
<test attrDate="2016-1-10">
</test>
element
<test attrDate="2015-1-10">
</test>
element
<test attrDate="2017-1-10">
</test>
So the correct results but unsorted.
Question
How can I sort by an attribute in a MarkLogic cts query?
Further Background
I have an index set up on that attribute, here is the config:
(This can index be created at http://localhost:8001/ > summary > YOURDATABASE-content > Attribute Range Indexes > Add, although I added it via Roxy)
It turns out this was a simple data issue (which I found in the last 5 seconds before posting this)
2016-01-10 is the 10th of January 2016
2016-1-10 is a malformed string that MarkLogic just ignores
I have a big XML file that I must read with XmlReader because it can not be loaded into memory. This XML is formatted in this way (is a reduced version):
<?xml version="1.0" encoding="windows-1252"?>
<Products>
<Product>
<Code>A14</Code>
<Name>Name1</Name>
<Manufacturer>
<Name>ManufacturerName</Name>
</Manufacturer>
<ProdCategories>
<ProdCategory>
<Code>015</Code>
<Name>ProdCategoryName</Name>
</ProdCategory>
</ProdCategories>
<Barcodes> <!-- note this line -->
</Barcodes>
</Product>
<Product>
<Code>A15</Code>
<Name>Name2</Name>
<Manufacturer>
<Name>ManufacturerName</Name>
</Manufacturer>
<ProdCategories>
<ProdCategory>
<Code>016</Code>
<Name>ProdCategoryName</Name>
</ProdCategory>
</ProdCategories>
<Barcodes>
<Barcode>
<Code>1234567890</Code> <!-- note this line -->
</Brcode>
</Barcodes>
</Product>
Note the <Barcode> <Code> elements: in the first <product> is missing.
This is the code that I use for read it and for put these data in a database:
XmlReader reader = XmlReader.Create("Products.xml");
reader.MoveToContent();
do
{
reader.ReadToFollowing("Code");
code = reader.ReadElementContentAsString();
reader.ReadToFollowing("Name");
Name = reader.ReadElementContentAsString();
reader.ReadToFollowing("Name");
ManufacturerName = reader.ReadElementContentAsString();
reader.ReadToFollowing("Code");
ProdCategoryCode = reader.ReadElementContentAsString();
reader.ReadToFollowing("Code");
BarcodeCode = reader.ReadElementContentAsString();
//Here I use "code", "Name", "ManufacturerName" variables to insert into a database
} while (reader.Read());
reader.Close();
All XML tags are present in all products except the <Barcodes> childs (<Barcode><Code>) that is present only on some product, then I cannot jump at next "code" with last ReadToFollowing because if not present I capture the first <product><code>.
I cant control XML output and cant modify it (is third-party).
There's a way to "ReadToFollowing('<Barcodes><Barcode><Code>')" so that I can specific what should seek and if there is not found I can jump it?
Thank you for your help, excuse my bad english.
I would suggest to pull each Product element into a tree model, using either https://msdn.microsoft.com/en-us/library/system.xml.linq.xnode.readfrom(v=vs.110).aspx or https://msdn.microsoft.com/en-us/library/system.xml.xmldocument.readnode(v=vs.110).aspx, then you can use LINQ to XML query methods or XPath to read out the data of each Product in a safe way while maintaining a low memory footprint.
Using Xquery, how can I search the file below (consisting of many items), for all items with 'XC' in the part-number (there are many), then for matches return all 3 of the interesting data elements (part-number, part-name, and name)? The return is the main problem--my attempts result in every permutation of the interesting data elements. Thank you!
<catalog>
<item>
<description>
<partref>
<part-id>
<part-number>XC51222</part-number>
</part-id>
</partref>
<part-name>DSP, Network Vectoring<part-name>
<vendors>
<vendor1>
<pay-to>
<name>JCOF Industries</name>
</pay-to>
</vendor1>
</vendors>
</description>
</item>
<item>
</item>
[many items…]
</catalog>
xquery version "1.0";
let $sep := ','
for $x in catalog/item
where fn:matches($x/description/partref/part-id/part-number, 'XC')
return fn:string-join( ($x/description/partref/part-id/part-number/text(), $x/description/part-name/text(), $x/description/vendors/vendor1/pay-to/name/text()), $sep)