Combine multiple array based on composite key in xquery - xquery

I am facing an issue while combining element array based on two key that is docNo and item_no in xquery version 1.0
Below is the given xml sample input and output
sample XML Request:
<text>
<element>
<docNo>11111</docNo>
<item_no>001</item_no>
<text_line>SUPER PROFILE</text_line>
</element>
<element>
<docNo>1111</docNo>
<item_no>001</item_no>
<text_line>TOP SPOTS</text_line>
</element>
<element>
<docNo>1111</docNo>
<item_no>002</item_no>
<text_line>SUPER PROFILE</text_line>
</element>
<element>
<docNo>1111</docNo>
<item_no>002</item_no>
<text_line>TOP SPOTS</text_line>
</element>
<element>
<docNo>2222</docNo>
<item_no>002</item_no>
<text_line>PROILE</text_line>
</element>
output :
<text>
<element>
<docNo>11111</docNo>
<item_no>001</item_no>
<text>
<text_line>SUPER PROFILE</text_line>
<text_line>TOP SPOTS</text_line>
</text>
</element>
<element>
<docNo>11111</docNo>
<item_no>002</item_no>
<text>
<text_line>SUPER PROFILE</text_line>
<text_line>TOP SPOTS</text_line>
</text>
</element>
<element>
<docNo>2222</docNo>
<item_no>002</item_no>
<text>
<text_line>PROFILE</text_line>
</text>
</element>
I am using distinct-values in but it is merging both with item_no 001 and 002.
Thanks

In XQuery 3 you would use the group by clause with two grouping keys:
/*/element { node-name(.) } {
for $e at $pos in element
group by $dn := $e/docNo, $in := $e/item_no
order by head($pos)
return
<element>
{
head($e) ! (docNo, item_no),
<text>
{
$e/text_line
}
</text>
}
</element>
}
In XQuery 1 you can use distinct-values on a key concatenated from the two elements:
/*/element { node-name(.) } {
for $key in distinct-values(for $e in element return concat($e/docNo, '|', $e/item_no))
let $group := element[concat(docNo, '|', item_no) = $key]
return
<element>
{
$group[1]/(docNo | item_no),
<text>
{
$group/text_line
}
</text>
}
</element>
}

Related

endAdornment arrow taking too much space with the last character in Material-UI Autocomplete

<Autocomplete
{...defaultProps}
id="disable-close-on-select"
disableCloseOnSelect
renderInput={(params) => (
<TextField {...params} label="disableCloseOnSelect" variant="standard" />
)}
/>
This is the sandbox link.
endAdornment arrow taking too much space with the last character in Material-UI Autocomplete.
You can update the padding-right by targeting the element with the class MuiAutocomplete-inputRoot. You also need to use the double ampersand && to increase the CSS specificity so the property can be overridden:
import Autocomplete, { autocompleteClasses } from "#mui/material/Autocomplete";
export default function ComboBox() {
return (
<Autocomplete
options={top100Films}
inputValue="looooooooooooooooooooooooooooooong text"
sx={{
width: 300,
[`&& .${autocompleteClasses.inputRoot}`]: {
paddingRight: 2, // change this value to your preference
}
}}
renderInput={(params) => <TextField {...params} label="Movie" />}
/>
);
}
Live Demo

how to display table using a flatlist in react native (with 2 columns, one for id and one for date)

createTableFL(){
var { isLoading, tableData } = this.state;
return(
<ScrollView style={{marginTop:10}} >
<ScrollView horizontal={true}>
<View style={styles.containerT}>
<FlatList
data={tableData}
style={{flex:1,marginVertical:20}}
keyExtractor={(x,i)=>i}
renderItem={({item,i}) =>
{
<View>
<Text>{item.inventory_id}</Text>
<Text>{item.created_on}</Text>
</View>
}}
numColumns={1}
/>
</View>
</ScrollView>
</ScrollView>
)
}
set column number like this :numColumns={2}
Please check https://aboutreact.com/example-of-gridview-using-flatlist-in-react-native/ link for reference.
else you just change the number of columns of your table by assign value to numColumns={number of columns you want}.
Hope this works for you.

How to get a key with knowing only one value

I've been going back and forward with this thing for a week now and can't get to a solution with it. Basically I want to remove something from firebase database but the thing is that I don't know what key is. So I added a server timestamp which should be a unique thing and now I would like to find that timestamp in the database and remove that child/node, however u call this, to which that timestamp belongs.
This part creates views with the info from the database and when I would click on that image I would like to remove it from the database.
<View style={styles.itemsList}>
{this.props.items.map((item, index) => {
if (item.ttype == 0) {
return (
<View key={index} style={styles.viewHolderNegative}>
<TouchableOpacity onPress={() => this.removeSelected(item.timestamp)}>
<Image source={require('./assets/remove24.png')}></Image>
</TouchableOpacity>
<Text style={styles.textTransaction}>{item.name}</Text>
<Text style={[styles.textTransaction, { fontSize: 20 }]}>{item.date}</Text>
</View>
);
} else if (item.ttype == 1) {
return (
<View key={index} style={styles.viewHolderPositive}>
<TouchableOpacity onPress={() => this.removeSelected(item.timestamp)}>
<Image source={require('./assets/remove24.png')}></Image>
</TouchableOpacity>
<Text style={styles.textTransaction}>{item.name}</Text>
<Text style={[styles.textTransaction, { fontSize: 20 }]}>{item.date}</Text>
</View>
);
}
})}
</View>
I assume that you are aware of firebase methods, if not then check firebase docs for react-native,
you can achieve removing an item by remove() method but you will have to acknowledge which item to remove.
for that, you will have to give key in child(key) method.
see this,
firebase.database().ref('ITEMS').child('KEY').remove();
ITEMS is the collection name and KEY is your timestamp.

react-bootstrap-table misaligned header columns

I have the following:
Node.jsx
import React from 'react';
import {Col, Row, Tab, Tabs} from 'react-bootstrap';
import Alerts from './Alerts';
import Details from './Details';
import Family from './Family';
import Instances from './Instances';
module.exports = React.createClass({
displayName: 'Node',
render () {
return (
<Row>
<Col md={12}>
<Tabs defaultActiveKey={1}>
<Tab eventKey={1} title={'Details'}>
<Details />
</Tab>
<Tab eventKey={2} title={'Alerts'}>
<Alerts />
</Tab>
<Tab eventKey={3} title={'Family'}>
<Family />
</Tab>
<Tab eventKey={4} title={'Instances'}>
<Instances instances={this.props.nodeInstances}/>
</Tab>
</Tabs>
</Col>
</Row>
);
}
});
Instances.jsx
import React from 'react';
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
module.exports = React.createClass({
displayName: 'NodeInstances',
getDefaultProps () {
return {
selectRowOpts: {
mode: "radio",
clickToSelect: true,
hideSelectColumn: true,
bgColor: "rgb(238, 193, 213)",
onSelect: (row, isSelected) => { console.log(row, isSelected); }
}
};
},
render () {
var props = this.props;
return (
<BootstrapTable data={props.instances} hover condensed selectRow={props.selectRowOpts}>
<TableHeaderColumn dataField={'interval_value'} dataSort>{'Interval'}</TableHeaderColumn>
<TableHeaderColumn dataField={'status_name'} dataSort>{'Status'}</TableHeaderColumn>
<TableHeaderColumn dataField={'started_ts'} dataSort>{'Started'}</TableHeaderColumn>
<TableHeaderColumn dataField={'completed_ts'} dataSort>{'Completed'}</TableHeaderColumn>
<TableHeaderColumn dataField={'last_runtime'} dataSort>{'RT'}</TableHeaderColumn>
<TableHeaderColumn dataField={'attempts'} dataSort>{'Attempts'}</TableHeaderColumn>
<TableHeaderColumn dataField={'pid'} dataSort>{'PID'}</TableHeaderColumn>
<TableHeaderColumn dataField={'node_instance_id'} dataSort isKey>{'ID'}</TableHeaderColumn>
</BootstrapTable>
);
}
});
Here is what all that looks like:
Why are the header columns for the table misaligned? Further, when I select one of the headers to sort the table, or when I select one of the rows in the table, the columns become properly aligned with the headers. Did I miss something?
I was having the same issue, and I ended up discovering that I was importing the wrong CSS file. Make sure you're using one of the CSS files listed in here.
I also used table-layout: fixed and set a specific width on each TableHeaderColumn component.
Not the most ideal solution, but it's the only thing I've found that works.
I had same issue . This below import in the app.js solved my problem
import 'react-bootstrap-table/dist/react-bootstrap-table.min.css';
I had same issues, I tried adding fixed width to all rows but it is not a perfect solution. So finally I have created a dynamic width for each row's based on its text string length.
So my suggestion to make the width of every row dynamically(based on string length and also restricted that to 24).
In my below program I have done for loop to get the length of a string in that array and assigning max value as the width of that column(in your case its row)
for (let i = 0; i < (totalElementsinArray); i++) {
if(((obj[i]["Title"]).length)> ((obj[i]["1_Content"]).length) & ((obj[i]["Title"]).length) > 24 ){
heightlength=((obj[i]["Title"]).length)-5
} else {
if(((obj[i]["1_Content"]).length) > 24){
heightlength=((obj[i]["1_Content"]).length)-5
} else {
heightlength=24;
}
}
I've created a javascript function to get the widths of the real table headers and set them to the fixed table headers (wich actually is in another table) :
function fixTableCols(table) {
var _length = [];
var $table = $(table);
$table.find('th').each(function (index, headerCol) {
_length[index] = $(headerCol).width();
});
$table.parent().parent().find('.fixed-table-header').find('th').each(function (index, headerCol) {
$(headerCol).find('.th-inner ').css('width', _length[index]);
});
}
So, you can call this function after applying the bootstrapTable(), like this:
var $table = $('table');
$table.bootstrapTable();
fixTableCols($table);

Combining and grouping data from two XML files

I have an XML file bands.xml as below:
<?xml version="1.0" encoding="ISO-8859-1"?>
<bands>
<band>
<name>Metallica</name>
<nationality>American</nationality>
</band>
<band>
<name>Marilyn Manson</name>
<nationality>American</nationality>
</band>
</bands>
and another file listing their albums albums.xml as below:
<?xml version="1.0" encoding="ISO-8859-1"?>
<albums>
<album>
<title>Master of Puppets</title>
<band>Metallica</band>
<date>1986</date>
<genre>rock</genre>
</album>
<album>
<title>St. Anger</title>
<band>Metallica</band>
<date>2003</date>
<genre>rock</genre>
</album>
<album>
<title>The Golden Age of Grotesque</title>
<band>Marilyn Manson</band>
<date>2004</date>
<genre>rock</genre>
</album>
<album>
<title>Mechanical Animals</title>
<band>Marilyn Manson</band>
<date>1998</date>
<genre>pop</genre>
</album>
</albums>
What I wish to do is combine these 2 XML files into another processed XML file. The Xquery will list down all bands, and within it list all the albums associated with that particular band, group it by album genre (sorted alphabetically). This is further illustrated as in the XML file below:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<bands>
<band>
<name>Metallica</name>
<nationality>American</nationality>
<albums genre="rock">
<album date="1986">
<title>Master of Puppets</title>
</album>
<album date="2003">
<title>St. Anger</title>
</album>
</albums>
</band>
<band>
<name>Marilyn Manson</name>
<nationality>American</nationality>
<albums genre="pop">
<album date="1998">
<title>Mechanical Animals</title>
</album>
</albums>
<albums genre="rock">
<album date="2004">
<title>The Golden Age of Grotesque</title>
</album>
</albums>
</band>
</bands>
What I've managed to do is get all the band details part, and also list all associated albums produced by that band. However since I am using Xquery 1.0, it is really frustrating to group the albums according to genre!
The following should work using purely XQuery 1.0:
declare variable $bandsxml := doc("bands.xml");
declare variable $albumsxml := doc("albums.xml");
<bands>
{
for $findband in $bandsxml/bands/band
return
<band>
{
$findband/name,
$findband/nationality,
let $albums-per-band := $albumsxml/albums/album[band = $findband/name]
for $genre in distinct-values($albums-per-band/genre)
order by $genre
let $albums := $albums-per-band[genre = $genre]
return element {"albums"} {
attribute {"genre"} {$genre},
attribute {"active"} {string-join((xs:string(min($albums/date)), "-", xs:string(max($albums/date))), "")},
attribute {"count"} {count($albums)},
for $album in $albums
return element {"album"} {
attribute {"date"} {$album/date},
$album/title
}
}
}
</band>
}
</bands>
In the first for loop it gets all distinct genres per band. It then uses this information and $albums is a sequence of albums for one particular band having a certain genre.
Here is one way to do it in XQuery 3.0:
xquery version "3.0";
let $bands := <bands>
<band>
<name>Metallica</name>
<nationality>American</nationality>
</band>
<band>
<name>Marilyn Manson</name>
<nationality>American</nationality>
</band>
</bands>
let $albums := <albums>
<album>
<title>Master of Puppets</title>
<band>Metallica</band>
<date>1986</date>
<genre>rock</genre>
</album>
<album>
<title>St. Anger</title>
<band>Metallica</band>
<date>2003</date>
<genre>rock</genre>
</album>
<album>
<title>The Golden Age of Grotesque</title>
<band>Marilyn Manson</band>
<date>2004</date>
<genre>rock</genre>
</album>
<album>
<title>Mechanical Animals</title>
<band>Marilyn Manson</band>
<date>1998</date>
<genre>pop</genre>
</album>
</albums>
return
element { 'bands' } {
for $findband in $bands//band
return
element { 'band' } {
$findband/name,
$findband/nationality,
for $findalbum in $albums//album
let $genre := $findalbum/genre/text()
where $findalbum/band = $findband/name
group by $genre
order by $genre
return
element { 'albums' } {
attribute { 'genre' } { $genre },
attribute { 'active' } { fn:min($findalbum/date/text()) ||'-' || fn:max($findalbum/date/text()) },
attribute { 'count' } { fn:count($findalbum) },
for $album in $findalbum
return
element { 'album' } {
attribute { 'date' } { $album/date/text()},
$album/title
}
}
}
}

Resources