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
}
}
}
}
Related
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>
}
I'm working on a nextjs project and I am having an issue rending elements through jsx. This is my code:
{
this.state.projects.forEach((projects)=>{
<Project name={projects.name} id={projects.id} url={`/projects/${projects.id}`} description={projects.description} ownerUsername={projects.author.username} ownerImage={projects.author.image}/>
})
}
The component doesn't render.
You have to return an array for your use case using Array.prototype.map
{
this.state.projects.map((project)=> {
return (<Project
key={project.id} // don't forget the key prop
name={project.name}
id={project.id}
url={`/projects/${project.id}`}
description={project.description}
ownerUsername={project.author.username}
ownerImage={project.author.image}
/>
)
}
}
I have a bunch of logo's, generated with illustrator, that I would like to embed in my website directly. The svgs all have a <style> element where the styles are defined inside the svg element, something like this:
<svg>
<style>
.st1 { fill:#ff00ff; }
.st2 { fill:#ff3421; }
/* ... and so on */
</style>
<!-- svg paths and shapes -->
</svg>
The problem is that these styles interfer with each other. So if the last images defines .st21 {fill:#555555} this style is applied to all path with class="st21", including paths from all previously loaded svg images.
In another thread somebody suggested to wrap my svg-xml with an <object> tag, that doesn't seem to work.
How can I make sure that inline SVG styles are not interfering with each other, without touching the actual SVG code?
here's a pen to illustrate the problem: https://codepen.io/pwkip/pen/RLPgpW
I would suggest to export svg with appropriate CSS properties in the first place.
During export from Illustrator choose :style attributes it would be something like this in svg:
<path style="fill: red"></path>
It could increase your file size but it definitely do the job. I found a nice explanation here
I came up with a JavaScript solution. Although this might be a little overkill and slow if you use a lot of SVGs. But this works fine so far.
What I do is, I iterate over all SVGs and collect/parse their CSS styles. I collect all class names and properties and apply them manually onto the SVG elements.
const svgCollection = document.querySelectorAll( 'svg' );
function parseStyles( styleTag ) {
if ( !styleTag ) {
return {};
}
const classCollection = {};
const plain = styleTag.innerHTML;
const regex = /\.([^\s{]+)[\s]*\{([\s\S]+?)\}/;
const propertyRegex = /([\w\-]+)[\s]*:[\s]*([^;]+)/;
const result = plain.match( new RegExp( regex, 'g' ) );
if ( result ) {
result.forEach( c => {
const classResult = c.match( regex );
const propertiesResult = classResult[ 2 ].match( new RegExp( propertyRegex, 'g' ) );
const properties = propertiesResult.reduce( ( collection, item ) => {
const p = item.match( propertyRegex );
collection[ p[ 1 ] ] = p[ 2 ];
return collection;
}, {} );
classCollection[ classResult[ 1 ] ] = properties;
} );
return classCollection;
}
return {};
}
function applyProperties( element, properties ) {
if ( !properties ) {
return;
}
Object.keys( properties ).forEach( key => {
element.style[ key ] = properties[ key ];
} );
}
function applyStyles( element, styles ) {
const classNames = ( element.getAttribute( 'class' ) || '' ).split( ' ' );
classNames.forEach( c => {
applyProperties( element, styles[ c ] );
} );
element.setAttribute( 'class', '' );
}
for ( let i = 0; i < svgCollection.length; i += 1 ) {
const svg = svgCollection[ i ];
const styles = parseStyles( svg.querySelector( 'style' ) );
const elements = svg.querySelectorAll( '[class]' );
for ( let j = 0; j < elements.length; j += 1 ) {
applyStyles( elements[ j ], styles );
}
}
<p>this shape should be blue:</p>
<svg height="210" width="210">
<style>
.st1 {
fill:blue;
}
</style>
<polygon points="100,10 40,198 190,78 10,78 160,198" class="st1"/>
</svg>
<p>this shape should be red:</p>
<svg height="210" width="210">
<style>
.st1 {
fill:red;
}
</style>
<ellipse cx="105" cy="80" rx="100" ry="50" class="st1" />
</svg>
Even though this works great, I wouldn't suggest it (as mentioned in the comments at your question). Better to set CSS Properties to Presentation Attributes in Illustrater
im building a web app using a node js server with babel and react js.
in some pages im using the react-bootstrap-table tag in order to create a table (as shown below) that includes built-in filters of data, and i have 2 main problems:
1. the headers are misaligned with the data colums - bootstrap table tag transpiles into 2 html table tags which is what i think causes the problem in the first place. i've read some posts about the issue and it was supposed to be fixed in version 2.0.0 and im using version 2.9.0
im using the built in filters for some of the columns, which generates 2 input scrollers that are supposed to appear one next to each other in the column header but instead shows one under the other. again i've tried to look around but didnt find something useful.
im adding the source-code of the html rendered and a screenshot showing the table (im sorry in advance but the text in the image is mostly hebrew but it doesnt matter much to get the idea)
renderTable: function () {
return (
<div >
<button className="w3-btn w3-theme-d5 w3-margin-top w3-round-xxlarge" onClick={this.onClickAddButton}> + </button>
<BootstrapTable data={this.state.users} options={options} bordered={false} hover striped search searchPlaceholder={constantStrings.search_string}>
<TableHeaderColumn
dataField = 'personal.id'
dataAlign = 'right'
dataSort = {true}
filter = { {type: 'TextFilter', placeholder:constantStrings.enterID_string} }
isKey = {true}>
{constantStrings.userID_string}
</TableHeaderColumn>
<TableHeaderColumn
dataField = 'personal.firstName'
dataAlign = 'right'
dataSort = {true}
filter={ { type: 'TextFilter', placeholder:constantStrings.enterFirstName_string} }>
{constantStrings.firstName_string}
</TableHeaderColumn>
<TableHeaderColumn
dataField = 'personal.lastName'
dataAlign = 'right'
filter = { { type: 'TextFilter', placeholder:constantStrings.enterLastName_string} }>
{constantStrings.lastName_string}
</TableHeaderColumn>
<TableHeaderColumn
dataField = 'personal.sex'
dataAlign = 'right'
filterFormatted dataFormat={ helpers.enumFormatter } formatExtraData={ constantStrings.user_gender }
filter={ { type: 'SelectFilter', placeholder:constantStrings.selectGender_string, options: constantStrings.user_gender } }>
{constantStrings.gender_string}
</TableHeaderColumn>
<TableHeaderColumn
dataField = 'jobDetails.userType'
dataAlign = 'right'
filterFormatted dataFormat={ helpers.enumFormatter } formatExtraData={ constantStrings.user_role }
filter={ { type: 'SelectFilter', placeholder:constantStrings.selectRole_string, options: constantStrings.user_role } }>
{constantStrings.role_string}
</TableHeaderColumn>
<TableHeaderColumn
dataField = 'startDate'
dataAlign = 'right'
dataFormat={ dateFormatter }
filter={ { type: 'DateFilter' ,placeholder:constantStrings.selectStartDate_string} }>
{constantStrings.startDate_string}
</TableHeaderColumn>
<TableHeaderColumn
dataAlign = 'right'
dataField = 'button'
dataFormat = {this.editButton}>
"Edit"
</TableHeaderColumn>
<TableHeaderColumn
dataAlign = 'right'
dataField = 'button'
dataFormat = {this.deleteButton}>
"Delete"
</TableHeaderColumn>
</BootstrapTable>
</div>
)
},
I had this issue as well..
This is css issue (the file doesn't loaded).
If you are using
react-bootstrap-table Getting Started
from here
you should change:
<link rel="stylesheet" src="https://npmcdn.com/react-bootstrap-table/dist/react-bootstrap-table-all.min.css">
to:
<link rel="stylesheet" href="https://npmcdn.com/react-bootstrap-table/dist/react-bootstrap-table-all.min.css">
(in index.html file)
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);