create new structure and move elements with xslt - xslt

I have a rather badly formatted input xml that needs to be reorganized using xslt 1.0.
The hierarchy must be changed so that detail lines are divided in an upper and lower part, each containing a left and right part. I failed to create the desired output until now.
Can someone help me out, thanks in advance.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<document>
<Header_Label_Header_1>
<Label_Header_Header_Company>1001</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>1</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>PAR Wdfl Vivida bianco strukt.</Line_Print_Description_1>
<Line_Print_Description_2>30x60cm</Line_Print_Description_2>
</Detail_Line>
<Detail_Line>
<Line_Print_Description_1>PAR Wdfl Secret bianco 1.</Line_Print_Description_1>
<Line_Print_Description_2>29,5x59,5cm</Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_1>
<Header_Label_Header_2>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>2</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Brownwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line>
<Detail_Line>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Greywood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line>
<Detail_Line>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Blackwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_2>
<Header_Label_Header_3>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>3</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>RAK Fstzg Ardesia black gl.str</Line_Print_Description_1>
<Line_Print_Description_2>frb, R9, 30x60cm</Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_3>
<Header_Label_Header_4>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>4</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>BAUMIT KlebeSpachtel 25kg</Line_Print_Description_1>
<Line_Print_Description_2></Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_4>
<Header_Label_Header_1>
<Label_Header_Header_Company>1001</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>1</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>PAR Wdfl Vivida bianco strukt.</Line_Print_Description_1>
<Line_Print_Description_2>30x60cm</Line_Print_Description_2>
</Detail_Line>
<Detail_Line>
<Line_Print_Description_1>PAR Wdfl Secret bianco 1.</Line_Print_Description_1>
<Line_Print_Description_2>29,5x59,5cm</Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_1>
<Header_Label_Header_2>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>2</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Brownwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line>
<Detail_Line>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Greywood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line>
<Detail_Line>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Blackwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_2>
<Header_Label_Header_3>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>3</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>RAK Fstzg Ardesia black gl.str</Line_Print_Description_1>
<Line_Print_Description_2>frb, R9, 30x60cm</Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_3>
<Header_Label_Header_4>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>4</Label_Header_Header_Unique_Sequence_Number>
<Detail_Line>
<Line_Print_Description_1>BAUMIT KlebeSpachtel 25kg</Line_Print_Description_1>
<Line_Print_Description_2></Line_Print_Description_2>
</Detail_Line>
</Header_Label_Header_4>
</document>
The output must be like this:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<document>
<Header_Label_Upper>
<Label_Left>
<Label_Header_Header_Company>1001</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>1</Label_Header_Header_Unique_Sequence_Number>
</Label_Left>
<Detail_Line_Left>
<Line_Print_Description_1>PAR Wdfl Vivida bianco strukt.</Line_Print_Description_1>
<Line_Print_Description_2>30x60cm</Line_Print_Description_2>
</Detail_Line_Left>
<Detail_Line_Left>
<Line_Print_Description_1>PAR Wdfl Secret bianco 1.</Line_Print_Description_1>
<Line_Print_Description_2>29,5x59,5cm</Line_Print_Description_2>
</Detail_Line_Left>
<Label_Right>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>2</Label_Header_Header_Unique_Sequence_Number>
</Label_Right>
<Detail_Line_Right>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Brownwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line_Right>
<Detail_Line_Right>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Greywood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line_Right>
<Detail_Line_Right>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Blackwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line_Right>
</Header_Label_Upper>
<Header_Label_Lower>
<Label_Left>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>3</Label_Header_Header_Unique_Sequence_Number>
</Label_Left>
<Detail_Line_Left>
<Line_Print_Description_1>RAK Fstzg Ardesia black gl.str</Line_Print_Description_1>
<Line_Print_Description_2>frb, R9, 30x60cm</Line_Print_Description_2>
</Detail_Line_Left>
<Label_Right>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>4</Label_Header_Header_Unique_Sequence_Number>
</Label_Right>
<Detail_Line_Right>
<Line_Print_Description_1>BAUMIT KlebeSpachtel 25kg</Line_Print_Description_1>
<Line_Print_Description_2></Line_Print_Description_2>
</Detail_Line_Right>
</Header_Label_Lower>
<Header_Label_Upper>
<Label_Left>
<Label_Header_Header_Company>1001</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>1</Label_Header_Header_Unique_Sequence_Number>
</Label_Left>
<Detail_Line_Left>
<Line_Print_Description_1>PAR Wdfl Vivida bianco strukt.</Line_Print_Description_1>
<Line_Print_Description_2>30x60cm</Line_Print_Description_2>
</Detail_Line_Left>
<Detail_Line_Left>
<Line_Print_Description_1>PAR Wdfl Secret bianco 1.</Line_Print_Description_1>
<Line_Print_Description_2>29,5x59,5cm</Line_Print_Description_2>
</Detail_Line_Left>
<Label_Right>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>2</Label_Header_Header_Unique_Sequence_Number>
</Label_Right>
<Detail_Line_Right>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Brownwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line_Right>
<Detail_Line_Right>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Greywood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line_Right>
<Detail_Line_Right>
<Line_Print_Description_1>IRS Fstzg Porcelainw.Blackwood</Line_Print_Description_1>
<Line_Print_Description_2>frb. R9, 15x120cm</Line_Print_Description_2>
</Detail_Line_Right>
</Header_Label_Upper>
<Header_Label_Lower>
<Label_Left>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>3</Label_Header_Header_Unique_Sequence_Number>
</Label_Left>
<Detail_Line>
<Line_Print_Description_1>RAK Fstzg Ardesia black gl.str</Line_Print_Description_1>
<Line_Print_Description_2>frb, R9, 30x60cm</Line_Print_Description_2>
</Detail_Line>
<Label_Right>
<Label_Header_Header_Company>00500</Label_Header_Header_Company>
<Label_Header_Header_Unique_Sequence_Number>4</Label_Header_Header_Unique_Sequence_Number>
</Label_Right>
<Detail_Line>
<Line_Print_Description_1>BAUMIT KlebeSpachtel 25kg</Line_Print_Description_1>
<Line_Print_Description_2></Line_Print_Description_2>
</Detail_Line>
</Header_Label_Lower>
</document>

Given your example XML, the following XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" indent="yes" standalone="no"/>
<xsl:strip-space elements="*"/>
<!-- The identity transform. -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- Match the root node. -->
<xsl:template match="document">
<xsl:copy>
<!-- Restructure each subset of four Header_Label_Header elements. -->
<xsl:for-each select="*[position() mod 4 = 1]">
<xsl:call-template name="subset">
<xsl:with-param name="subset-nodes" select=". | following-sibling::*[position() < 4]"/>
</xsl:call-template>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template name="subset">
<xsl:param name="subset-nodes"/>
<!-- Select the first and third elements and give them appropriate upper/lower labels. -->
<xsl:for-each select="$subset-nodes[position() mod 2 = 1]">
<xsl:choose>
<xsl:when test="position() = 1">
<Header_Label_Upper>
<!-- Select this element and the one that follows it. -->
<xsl:apply-templates select=". | following-sibling::*[position() < 2]"/>
</Header_Label_Upper>
</xsl:when>
<xsl:otherwise>
<Header_Label_Lower>
<!-- Select this element and the one that follows it. -->
<xsl:apply-templates select=". | following-sibling::*[position() < 2]"/>
</Header_Label_Lower>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<!-- Match the Header_Label_Header elements and give them appropriate left/right labels. -->
<xsl:template match="*[contains(local-name(), 'Header_Label_Header_')]">
<xsl:choose>
<xsl:when test="position() = 1">
<Label_Left>
<xsl:apply-templates select="*[contains(local-name(), 'Label_Header_Header_')]"/>
</Label_Left>
<xsl:apply-templates select="Detail_Line" mode="Left"/>
</xsl:when>
<xsl:otherwise>
<Label_Right>
<xsl:apply-templates select="*[contains(local-name(), 'Label_Header_Header_')]"/>
</Label_Right>
<xsl:apply-templates select="Detail_Line" mode="Right"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Detail_Line" mode="Left">
<Detail_Line_Left>
<xsl:apply-templates/>
</Detail_Line_Left>
</xsl:template>
<xsl:template match="Detail_Line" mode="Right">
<Detail_Line_Right>
<xsl:apply-templates/>
</Detail_Line_Right>
</xsl:template>
</xsl:stylesheet>
output the desired XML.
The template could probably be improved as there is a bit of duplicated code, but it does the job.

Related

XSLT 2.0 sort using letters and numbers

I have a sequence of strings that look like this:
B5 C10 C8 D11 D13 D3 D7 D9 E12 E8
I did the <xsl:perform-sort and <xsl:sort, based on the default data-type="text" and it's working correctly. But I would like to further sort so that after the letter the values are sorted numerically:
B5 C8 C10 D3 D7 D9 D11 D13 E8 E12
Any suggestions on how to do that? Thanks!
Edited to add my code:
<xsl:variable name="pns1" as="xs:string*">
<xsl:perform-sort select="distinct-values($combo1/*:pin/*:pkg[$pos]/*:pn/#n)">
<xsl:sort select="."/>
</xsl:perform-sort>
</xsl:variable>
<xsl:variable name="pns2" as="xs:string*">
<xsl:perform-sort select="$pns1">
<xsl:sort select="." data-type="number"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:message select="$pns2"/>
Saxon allows you a parameter alphanumeric="yes" on a collation URI, see https://www.saxonica.com/html/documentation11/localization/unicode-collation-algorithm/ so e.g.
'B5 C10 C8 D11 D13 D3 D7 D9 E12 E8'
=> tokenize('\s+')
=> sort('http://www.w3.org/2013/collation/UCA?alphanumeric=yes')
gives
B5 C8 C10 D3 D7 D9 D11 D13 E8 E12
.
Online fiddle with Saxon XQuery (but XPath/XSLT support it the same): https://xqueryfiddle.liberty-development.net/jyH9Xvk.
Using numeric=yes;fallback=yes might even give better compatibility between the various Saxon editions (HE, PE, EE) and platforms (Java, .NET):
'B5 C10 C8 D11 D13 D3 D7 D9 E12 E8'
=> tokenize('\s+')
=> sort('http://www.w3.org/2013/collation/UCA?numeric=yes;fallback=yes')
or even SaxonJS.
Consider the following example:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="strings" select="('D13', 'B5', 'C10', 'E12', 'C8', 'D11', 'D3', 'E8', 'D7', 'D9')" />
<xsl:template match="/">
<result>
<xsl:perform-sort select="$strings">
<xsl:sort select="substring(., 1, 1)"/>
<xsl:sort select="substring(., 2)" data-type="number"/>
</xsl:perform-sort>
</result>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<result>B5 C8 C10 D3 D7 D9 D11 D13 E8 E12</result>

How to modify a SVG attribute using XSLT

How can I modify a SVG file by using XSLT?
I like to modify the following SVG (cutout) file:
<svg width="834px" height="707.5px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="visible">
<defs>
<symbol id="E003" viewBox="0 0 1000 1000" overflow="inherit">
<path transform="scale(1,-1)" d="M0 -0c49 0 97.5 -2.26367 135.5 4.73633c206 95 258.5 264.264 263.5 271.264c0 1 -14 7 -15 6c-88 -154 -251 -167 -321 -170c-1 0 -63 -1 -63 -1v-111z" />
</symbol>
<symbol id="E004" viewBox="0 0 1000 1000" overflow="inherit">
<path transform="scale(1,-1)" d="M0 0c49 0 97.5 2.26367 135.5 -4.73633c206 -95 258.5 -264.264 263.5 -271.264c0 -1 -14 -7 -15 -6c-88 154 -251 167 -321 170c-1 0 -63 1 -63 1v111z" />
</symbol>
<symbol id="E050" viewBox="0 0 1000 1000" overflow="inherit">
<path transform="scale(1,-1)" d="M441 -245c-23 -4 -48 -6 -76 -6c-59 0 -102 7 -130 20c-88 42 -150 93 -187 154c-26 44 -43 103 -48 176c-4 60 11 123 44 189c29 57 65 106 110 148s96 85 153 127c-3 16 -8 46 -13 92c-4 43 -5 73 -5 89c0 117 16 172 69 257c34 54 64 82 89 82c21 0 43 -30 69 -92 s39 -115 41 -159c2 -120 -19 -173 -67 -256c-13 -20 -63 -90 -98 -118c-13 -9 -25 -19 -37 -29l31 -181c8 1 18 2 28 2c58 0 102 -12 133 -35c59 -43 92 -104 98 -184c11 -135 -80 -229 -180 -270c8 -57 17 -110 25 -162c5 -31 6 -58 6 -80c0 -30 -5 -53 -14 -70 c-35 -64 -88 -99 -158 -103c-42 -3 -83 6 -124 26c-50 24 -77 59 -80 105c-2 34 5 63 20 87c18 28 45 42 79 44c51 4 99 -40 103 -87c4 -56 -30 -94 -105 -115c17 -24 51 -36 102 -36c62 0 116 43 140 85c9 16 13 41 13 74c0 20 -1 42 -5 67c-8 53 -18 106 -26 159zM461 939 c-95 0 -135 -175 -135 -286c0 -24 2 -48 5 -71c50 39 92 82 127 128c43 57 63 106 60 148c-4 54 -23 82 -57 81zM406 119l54 -326c80 27 116 88 109 184c-7 99 -62 146 -163 142zM382 117c-74 -2 -132 -50 -128 -127c2 -46 43 -99 75 -115c-3 -2 -7 -5 -10 -10 c-70 33 -116 88 -123 172c-5 73 42 135 88 170c23 17 49 29 78 36l-29 170c-21 -13 -52 -37 -92 -73c-50 -44 -86 -84 -109 -119c-49 -75 -71 -140 -67 -195c5 -68 35 -127 93 -176s125 -73 203 -73c25 0 50 3 75 9c-19 111 -36 221 -54 331z" />
</symbol>
<symbol id="E260" viewBox="0 0 1000 1000" overflow="inherit">
<path transform="scale(1,-1)" d="M20 110c32 16 54 27 93 27c26 0 35 -3 54 -13c13 -7 24 -20 27 -38l4 -25c0 -28 -16 -57 -45 -89c-23 -25 -39 -44 -65 -68l-88 -79v644h20v-359zM90 106c-32 0 -48 -10 -70 -29v-194c31 31 54 59 71 84c21 32 32 59 32 84c0 9 1 16 1 20c0 14 -3 21 -11 30l-8 3z" />
</symbol>
<symbol id="E0A4" viewBox="0 0 1000 1000" overflow="inherit">
<path transform="scale(1,-1)" d="M0 -39c0 68 73 172 200 172c66 0 114 -37 114 -95c0 -84 -106 -171 -218 -171c-64 0 -96 30 -96 94z" />
</symbol>
<symbol id="E262" viewBox="0 0 1000 1000" overflow="inherit">
<path transform="scale(1,-1)" d="M136 186v169h17v-164l44 14v-91l-44 -14v-165l44 12v-91l-44 -13v-155h-17v150l-76 -22v-155h-17v149l-43 -13v90l43 14v167l-43 -14v92l43 13v169h17v-163zM60 73v-167l76 22v168z" />
</symbol>
</defs>
<style type="text/css">g.page-margin{font-family:Times;} g.tempo{font-weight:bold;} g.dir, g.dynam, g.mNum{font-style:italic;} g.label{font-weight:normal;}</style>
<svg class="definition-scale" viewBox="0 0 16680 14150">
<g class="page-margin" transform="translate(500, 500)">
<g class="system" id="system-0000000155158177">
<path d="M2099 720 L2099 5782" stroke="#000000" stroke-width="27" />
<use xlink:href="#E003" x="1919" y="720" height="720px" width="720px" />
<use xlink:href="#E004" x="1919" y="5782" height="720px" width="720px" />
<rect x="1919" y="702" height="5098" width="90" />
<use xlink:href="#E003" x="1797" y="720" height="720px" width="720px" />
<use xlink:href="#E004" x="1797" y="2880" height="720px" width="720px" />
<rect x="1797" y="702" height="2196" width="90" />
<g class="labelAbbr" id="labelAbbr-0000001982553912">
<text x="1546" y="1170" text-anchor="end" font-size="0px">
<tspan class="text" id="text-0000000427332132">
<tspan font-size="405px" class="text">C Tpt. 1</tspan>
</tspan>
</text>
</g>
<g class="labelAbbr" id="labelAbbr-0000001715657114">
<text x="1546" y="2610" text-anchor="end" font-size="0px">
<tspan class="text" id="text-0000000786186729">
<tspan font-size="405px" class="text">C Tpt. 2</tspan>
</tspan>
</text>
</g>
<g class="labelAbbr" id="labelAbbr-0000000404188205">
<text x="1816" y="4072" text-anchor="end" font-size="0px">
<tspan class="text" id="text-0000000700385974">
<tspan font-size="405px" class="text">Tbn.</tspan>
</tspan>
</text>
</g>
<g class="labelAbbr" id="labelAbbr-0000001796530924">
<text x="1816" y="5512" text-anchor="end" font-size="0px">
<tspan class="text" id="text-0000000675162848">
<tspan font-size="405px" class="text">B. Tbn.</tspan>
</tspan>
</text>
</g>
<g class="sb" id="sb-0000001000252933" />
<g class="measure" id="d1e4299">
<g class="mNum autogenerated" id="mnum-0000001212157683">
<text x="2086" y="450" text-anchor="middle" font-size="0px">
<tspan class="text" id="text-0000001704302739">
<tspan font-size="324px" class="text">22</tspan>
</tspan>
</text>
</g>
<g class="staff" id="staff-0000001329456927">
<path d="M2086 720 L7292 720" stroke="#000000" stroke-width="13" />
<path d="M2086 900 L7292 900" stroke="#000000" stroke-width="13" />
<path d="M2086 1080 L7292 1080" stroke="#000000" stroke-width="13" />
<path d="M2086 1260 L7292 1260" stroke="#000000" stroke-width="13" />
<path d="M2086 1440 L7292 1440" stroke="#000000" stroke-width="13" />
<g class="clef" id="clef-0000001591308631">
<use xlink:href="#E050" x="2176" y="1260" height="720px" width="720px" />
</g>
<g class="keySig" id="keysig-0000000362821479">
<use xlink:href="#E260" x="2857" y="1080" height="720px" width="720px" />
</g>
<g class="layer" id="layer-0000001762708701">
<g class="note" id="d1e4305">
<use xlink:href="#E0A4" x="3559" y="1350" height="720px" width="720px" />
<g class="stem">
<rect x="3767" y="720" height="608" width="18" />
</g>
<g class="accid" id="accid-0000001439359008">
<use xlink:href="#E262" x="3364" y="1350" height="720px" width="720px" />
</g>
</g>
<g class="note" id="d1e4323">
<use xlink:href="#E0A4" x="4423" y="1350" height="720px" width="720px" />
<g class="stem">
<rect x="4631" y="720" height="608" width="18" />
</g>
<g class="accid" id="accid-0000000550318292" />
</g>
<g class="note" id="d1e4339">
<use xlink:href="#E0A4" x="5551" y="1260" height="720px" width="720px" />
<g class="stem">
<rect x="5759" y="630" height="608" width="18" />
</g>
</g>
<g class="note" id="d1e4353">
<use xlink:href="#E0A4" x="6415" y="900" height="720px" width="720px" />
<g class="stem">
<rect x="6415" y="922" height="608" width="18" />
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
</svg>
I want to change the color for the symbol id="E050". To achieve this I tried to add the attribute fill="#ff0000" to the symbol definition.
This is the current version of my XSL file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//symbol[#id='E050']">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="fill">#ff0000</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
How can I modify the XSL file that the color for the symbol id="E050 is changed but the rest is not modified?
To test the modification I'm using the online tool https://www.w3schools.com/xml/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog_ex1.
Change this line...
<xsl:template match="//symbol[#id='E050']">
To this line....
<xsl:template match="svg:symbol[#id='E050']">
(Note the // prefix is not necessary in a template match)
Although you have a default namespace declaration in your XSLT (xmlns="http://www.w3.org/2000/svg") this only applies to unprefixed elements in your XSLT (which also happens to be an XML document), not Xpath expressions in attributes. This doing a match on symbol[#id='E050'] is trying to match a symbol element in no namespace.
Alternatively, if you could use XSLT 2.0, you could add this line to the xsl:stylesheet element, as this would then mean unprefixed element names in xpath expressions would be given a namespace
xpath-default-namespace="http://www.w3.org/2000/svg"

Merging lines in chess ply sequences

I have a file containing the ply sequences of multiple chess games. Games are separated by one or more new lines and the corresponding ply sequence of each game can be also split into multiple lines.
I would like to merge all lines corresponding to the same game, so as to have only one line per game. I have tried different options, but none worked. A remark is that the file contains more than 14M games, so I need a fast solution. I work on Linux.
Example:
e4 e5 Bb5 c6 Bc4 b5 Bxf7+ Kxf7 Nf3 Qf6 d4 d6 dxe5 dxe5
Bg5 Qe6 Nc3 Be7 Be3 Nf6 b4 Rd8 Ng5+ Kg8 Nd5 Qd6 Qf3 cxd5
Bc5 Qe6 Nxe6 Bxe6 Bxe7
e4 e5 Nf3 Qf6 Bc4 Bc5 Nc3 c6 Na4 Bb4 c3 Ba5 Nc5 d6 Nb3
Bb6 d4 h6 dxe5 dxe5 O-O Ne7 Be3 Nd7 Bxb6 Nxb6 Be2 O-O
Nc5 Ng6 b4 Nf4 Nd3 Rd8 Qc2 Nc4 Nxf4 Na3 Qb3 Qxf4
Qxa3 Qxe4 Rfe1 f6 Qb3+ Kh8 Bd1 Qf4 Bc2 Bg4 Re4 Qf5 Rxe5
Qd7 Re3 Qd6 Nh4 Qd5 Ng6+ Kh7 Ne7+ f5 Nxd5 Rxd5 c4 Rd2
h3 Bh5 Bxf5+ Kh8
e4 e5 Nf3 Nc6 Bb5 Nf6 Bxc6 bxc6 O-O d6 h3 Nxe4 Re1 Bf5
d4 f6 dxe5 fxe5 Nbd2 Nxd2 Bxd2 Be7 Qc1 O-O c3 h6 c4 e4
Nd4 Qd7 b3 d5 Nxf5 Qxf5 Be3 Bf6 Rb1 d4 Bd2 c5
d4 Nf6 Nc3 d5 Bg5 Ne4 Nxe4 dxe4 c3 h6 Be3 e6 Qc2 f5 g4
Be7 Bg2 O-O O-O-O Nd7 d5 Nb6 dxe6 Qe8 gxf5 Rxf5 Bxe4 Rf8
Bh7+ Kh8 Bg6
Should become:
e4 e5 Bb5 c6 Bc4 b5 Bxf7+ Kxf7 Nf3 Qf6 d4 d6 dxe5 dxe5 Bg5 Qe6 Nc3 Be7 Be3 Nf6 b4 Rd8 Ng5+ Kg8 Nd5 Qd6 Qf3 cxd5 Bc5 Qe6 Nxe6 Bxe6 Bxe7
e4 e5 Nf3 Qf6 Bc4 Bc5 Nc3 c6 Na4 Bb4 c3 Ba5 Nc5 d6 Nb3 Bb6 d4 h6 dxe5 dxe5 O-O Ne7 Be3 Nd7 Bxb6 Nxb6 Be2 O-O Nc5 Ng6 b4 Nf4 Nd3 Rd8 Qc2 Nc4 Nxf4 Na3 Qb3 Qxf4 Qxa3 Qxe4 Rfe1 f6 Qb3+ Kh8 Bd1 Qf4 Bc2 Bg4 Re4 Qf5 Rxe5 Qd7 Re3 Qd6 Nh4 Qd5 Ng6+ Kh7 Ne7+ f5 Nxd5 Rxd5 c4 Rd2 h3 Bh5 Bxf5+ Kh8
e4 e5 Nf3 Nc6 Bb5 Nf6 Bxc6 bxc6 O-O d6 h3 Nxe4 Re1 Bf5 d4 f6 dxe5 fxe5 Nbd2 Nxd2 Bxd2 Be7 Qc1 O-O c3 h6 c4 e4 Nd4 Qd7 b3 d5 Nxf5 Qxf5 Be3 Bf6 Rb1 d4 Bd2 c5
d4 Nf6 Nc3 d5 Bg5 Ne4 Nxe4 dxe4 c3 h6 Be3 e6 Qc2 f5 g4 Be7 Bg2 O-O O-O-O Nd7 d5 Nb6 dxe6 Qe8 gxf5 Rxf5 Bxe4 Rf8 Bh7+ Kh8 Bg6
With awk, you can set the record separator to the empty string, which makes records being separated by blank lines. Then you replace for each record the newlines with a space:
awk -v RS="" '{gsub("\n", " ")} 1' infile
Or, as an alternative, with sed:
sed ':a;N;/\n$/!s/\n//;ta;s/\n$//;/^$/d' infile
This works as follows:
:label # Label to jump back to
N # Append next line to pattern sapce
/\n$/! s/\n// # If pattern space does not end with newline, remove newline
t label # Jump back to label if we changed something
s/\n$// # Remove trailing newline
/^$/ d # Delete empty line
The last command isn't strictly necessary for the given input, but if there are more than two consecutive empty lines, there would be empty output lines without it. It's just there to make the sed command equivalent to the awk command.

Why does base class destructor call free

I am compiling a C++ program for a NIOS II core with very limited memory. Since it is an embedded system we are not using a heap either. Since we added inheritance to our code we saw that malloc and free (and related functions) was being build into our binary thus increasing its size a number of kilobytes.
We have one pure virtual base class, StatisticsApi and one derived class Statistics. Statistics and they both have virtual destructors defined.
We are compiling with Alteras GCC with fno-rtti and -fno_expections and are also defined our own __cxa_pure_virtual().
Looking closer into it we see that delete is called from the destructors (and thus free). Why is that? What memory is it trying to free?
Here is the assembler for the destructors:
0000c6b8 <_ZN7Namespace12StatisticsD0Ev>:
c6b8: defffd04 addi sp,sp,-12
c6bc: dfc00215 stw ra,8(sp)
c6c0: df000115 stw fp,4(sp)
c6c4: df000104 addi fp,sp,4
c6c8: e13fff15 stw r4,-4(fp)
c6cc: 00c000b4 movhi r3,2
c6d0: 18c74b04 addi r3,r3,7468
c6d4: e0bfff17 ldw r2,-4(fp)
c6d8: 10c00015 stw r3,0(r2)
c6dc: e13fff17 ldw r4,-4(fp)
c6e0: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c6e4: 00800044 movi r2,1
c6e8: 10803fcc andi r2,r2,255
c6ec: 1005003a cmpeq r2,r2,zero
c6f0: 1000021e bne r2,zero,c6fc <_ZN7LinCtrl12TxStatisticsD0Ev+0x44>
c6f4: e13fff17 ldw r4,-4(fp)
c6f8: 000c8e00 call c8e0 <_ZdlPv>
c6fc: e037883a mov sp,fp
c700: dfc00117 ldw ra,4(sp)
c704: df000017 ldw fp,0(sp)
c708: dec00204 addi sp,sp,8
c70c: f800283a ret
0000c710 <_ZN7Namespace12StatisticsD1Ev>:
c710: defffd04 addi sp,sp,-12
c714: dfc00215 stw ra,8(sp)
c718: df000115 stw fp,4(sp)
c71c: df000104 addi fp,sp,4
c720: e13fff15 stw r4,-4(fp)
c724: 00c000b4 movhi r3,2
c728: 18c74b04 addi r3,r3,7468
c72c: e0bfff17 ldw r2,-4(fp)
c730: 10c00015 stw r3,0(r2)
c734: e13fff17 ldw r4,-4(fp)
c738: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c73c: 0005883a mov r2,zero
c740: 10803fcc andi r2,r2,255
c744: 1005003a cmpeq r2,r2,zero
c748: 1000021e bne r2,zero,c754 <_ZN7Namespace12StatisticsD1Ev+0x44>
c74c: e13fff17 ldw r4,-4(fp)
c750: 000c8e00 call c8e0 <_ZdlPv>
c754: e037883a mov sp,fp
c758: dfc00117 ldw ra,4(sp)
c75c: df000017 ldw fp,0(sp)
c760: dec00204 addi sp,sp,8
c764: f800283a ret
0000c768 <_ZN7Namespace12StatisticsD2Ev>:
c768: defffd04 addi sp,sp,-12
c76c: dfc00215 stw ra,8(sp)
c770: df000115 stw fp,4(sp)
c774: df000104 addi fp,sp,4
c778: e13fff15 stw r4,-4(fp)
c77c: 00c000b4 movhi r3,2
c780: 18c74b04 addi r3,r3,7468
c784: e0bfff17 ldw r2,-4(fp)
c788: 10c00015 stw r3,0(r2)
c78c: e13fff17 ldw r4,-4(fp)
c790: 000c7f00 call c7f0 <_ZN7Namespace15StatisticsApiD2Ev>
c794: 0005883a mov r2,zero
c798: 10803fcc andi r2,r2,255
c79c: 1005003a cmpeq r2,r2,zero
c7a0: 1000021e bne r2,zero,c7ac <_ZN7Namespace12StatisticsD2Ev+0x44>
c7a4: e13fff17 ldw r4,-4(fp)
c7a8: 000c8e00 call c8e0 <_ZdlPv>
c7ac: e037883a mov sp,fp
c7b0: dfc00117 ldw ra,4(sp)
c7b4: df000017 ldw fp,0(sp)
c7b8: dec00204 addi sp,sp,8
c7bc: f800283a ret
And here are the destructors for the base class:
0000c7f0 <_ZN7Namespace15StatisticsApiD2Ev>:
c7f0: defffd04 addi sp,sp,-12
c7f4: dfc00215 stw ra,8(sp)
c7f8: df000115 stw fp,4(sp)
c7fc: df000104 addi fp,sp,4
c800: e13fff15 stw r4,-4(fp)
c804: 00c000b4 movhi r3,2
c808: 18c76204 addi r3,r3,7560
c80c: e0bfff17 ldw r2,-4(fp)
c810: 10c00015 stw r3,0(r2)
c814: 0005883a mov r2,zero
c818: 10803fcc andi r2,r2,255
c81c: 1005003a cmpeq r2,r2,zero
c820: 1000021e bne r2,zero,c82c <_ZN7Namespace15StatisticsApiD2Ev+0x3c>
c824: e13fff17 ldw r4,-4(fp)
c828: 000c8e00 call c8e0 <_ZdlPv>
c82c: e037883a mov sp,fp
c830: dfc00117 ldw ra,4(sp)
c834: df000017 ldw fp,0(sp)
c838: dec00204 addi sp,sp,8
c83c: f800283a ret
0000c840 <_ZN7LinCtrl15TxStatisticsApiD0Ev>:
c840: defffd04 addi sp,sp,-12
c844: dfc00215 stw ra,8(sp)
c848: df000115 stw fp,4(sp)
c84c: df000104 addi fp,sp,4
c850: e13fff15 stw r4,-4(fp)
c854: 00c000b4 movhi r3,2
c858: 18c76204 addi r3,r3,7560
c85c: e0bfff17 ldw r2,-4(fp)
c860: 10c00015 stw r3,0(r2)
c864: 00800044 movi r2,1
c868: 10803fcc andi r2,r2,255
c86c: 1005003a cmpeq r2,r2,zero
c870: 1000021e bne r2,zero,c87c <_ZN7Namespace15StatisticsApiD0Ev+0x3c>
c874: e13fff17 ldw r4,-4(fp)
c878: 000c8e00 call c8e0 <_ZdlPv>
c87c: e037883a mov sp,fp
c880: dfc00117 ldw ra,4(sp)
c884: df000017 ldw fp,0(sp)
c888: dec00204 addi sp,sp,8
c88c: f800283a ret
0000c890 <_ZN7Namespace15StatisticsApiD1Ev>:
c890: defffd04 addi sp,sp,-12
c894: dfc00215 stw ra,8(sp)
c898: df000115 stw fp,4(sp)
c89c: df000104 addi fp,sp,4
c8a0: e13fff15 stw r4,-4(fp)
c8a4: 00c000b4 movhi r3,2
c8a8: 18c76204 addi r3,r3,7560
c8ac: e0bfff17 ldw r2,-4(fp)
c8b0: 10c00015 stw r3,0(r2)
c8b4: 0005883a mov r2,zero
c8b8: 10803fcc andi r2,r2,255
c8bc: 1005003a cmpeq r2,r2,zero
c8c0: 1000021e bne r2,zero,c8cc <_ZN7Namespace15StatisticsApiD1Ev+0x3c>
c8c4: e13fff17 ldw r4,-4(fp)
c8c8: 000c8e00 call c8e0 <_ZdlPv>
c8cc: e037883a mov sp,fp
c8d0: dfc00117 ldw ra,4(sp)
c8d4: df000017 ldw fp,0(sp)
c8d8: dec00204 addi sp,sp,8
c8dc: f800283a ret
And finally delete:
0000c8e0 <_ZdlPv>:
c8e0: 20000126 beq r4,zero,c8e8 <_ZdlPv+0x8>
c8e4: 000ebf01 jmpi ebf0 <free>
c8e8: f800283a ret
And here is a link to the instruction set for NIOS II for reference: http://www.altera.com/literature/hb/nios2/n2cpu_nii51017.pdf
The two solutions/workarounds we found were:
Redefining new/delete as empty functions (no heap so they shouldn't
be called anyway!) thus avoiding the call to free.
Leaving the destructors undefined in C++ which makes them not get
instantiated in assembler either. Though the compiler will complain
that there is no virtual destructor.
Workarounds or not, why are the destructors calling free? What memory is it trying to free!?! We have other destructors that are neither for base classes nor derived classes and they don't call free. This is how such a destructor looks like:
00005194 <_ZN7Namespace16OtherClassD2Ev>:
5194: defffe04 addi sp,sp,-8
5198: df000115 stw fp,4(sp)
519c: df000104 addi fp,sp,4
51a0: e13fff15 stw r4,-4(fp)
51a4: e037883a mov sp,fp
51a8: df000017 ldw fp,0(sp)
51ac: dec00104 addi sp,sp,4
51b0: f800283a ret
000051b4 <_ZN7Namespace16OtherClassD1Ev>:
51b4: defffe04 addi sp,sp,-8
51b8: df000115 stw fp,4(sp)
51bc: df000104 addi fp,sp,4
51c0: e13fff15 stw r4,-4(fp)
51c4: e037883a mov sp,fp
51c8: df000017 ldw fp,0(sp)
51cc: dec00104 addi sp,sp,4
51d0: f800283a ret
And also, in general, why are there multiple functions for each destructor (D0, D1 and D2)?
When you call delete on an object with a virtual destructor, it looks up the function to call in the virtual table. That function calls the destructor as well as freeing the memory, since only at the derived level does it know the proper pointer to pass to the free function.
The problem is that the compiler doesn't know that you are never calling delete. It still has to create the code even though it may never be used, just like any other virtual function.
Even though, as a general rule, destructors should be virtual in classes that have other virtual functions, this may be a valid exception. Making the destructor be protected in the base class will help avoid mistakes.

boost thread - use local variable as parameter

I'm writing a C++ class using boost threads. The purpose of the class is to start a new thread, generate in this thread every 2 seconds an object called LocationEstimatePF and call a callback function in another class, giving this LocationEstimatePF as parameter.
Something like this:
void Simulator::startSimulation() {
running_ = true;
sim_thread_ = new boost::thread(boost::bind(&Simulator::run, this));
}
void Simulator::run() {
for (;;) {
if(running_){
try {
//Generate estimate
LocationEstimatePF estimate(1,2,3,4,5);
engine_.updateLocationEstimate(estimate);
//Wait for 2 seconds for next estimate
boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
} catch (boost::thread_interrupted&) {
return;
}
}
}
}
The engine and thread are defined as a member variable in the .h file as follows:
InMapsEngine& engine_;
boost::thread* sim_thread_;
And the callback method in the Engine class:
void updateLocationEstimate(const LocationEstimatePF& estimate) { Log::info("Test");};
Now when I run startSimulation() above, I get a segmentation fault. Now, I know that engine_ is correctly set, I can even call other methods without a problem. I believe the problem lies in the local variable, do you guys have any idea? The "Test" in the engine is never printed.
Here the stack trace:
I/DEBUG (11781): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
I/DEBUG (11781): r0 00000000 r1 66da3e68 r2 00000001 r3 00000000
I/DEBUG (11781): r4 001e8480 r5 00000000 r6 00000000 r7 40490000
I/DEBUG (11781): r8 62055ab0 r9 66da3e68 sl 3f800000 fp 40000000
I/DEBUG (11781): ip 00000001 sp 66da3e60 lr 61864604 pc 616b0a4e cpsr 60000030
I/DEBUG (11781): d0 4158b82020000000 d1 3f110612c247fff9
I/DEBUG (11781): d2 400b8ae93f57e022 d3 400b8ae943697f55
I/DEBUG (11781): d4 c2ef3a464385c588 d5 407eb7ac40c0a412
I/DEBUG (11781): d6 40dd1ce4bec8a7a3 d7 0062e080400b8ae9
I/DEBUG (11781): d8 3fd9b1b440400000 d9 0000000000000000
I/DEBUG (11781): d10 0000000000000000 d11 0000000000000000
I/DEBUG (11781): d12 0000000000000000 d13 0000000000000000
I/DEBUG (11781): d14 0000000000000000 d15 0000000000000000
I/DEBUG (11781): d16 3fe0000000000000 d17 4158b82000000000
I/DEBUG (11781): d18 3fd7e1cb1c913900 d19 3fc41a88bb99a35a
I/DEBUG (11781): d20 0000000000000000 d21 3fac47489540ee39
I/DEBUG (11781): d22 3f8293cfee13fd75 d23 3f96eb1df9afa780
I/DEBUG (11781): d24 3f5871d465fee876 d25 3f6e1beddd51e95d
I/DEBUG (11781): d26 3f30d636137869f2 d27 3f439d2605c8ef21
I/DEBUG (11781): d28 3fe66819a15509c2 d29 3f13d11c3e64b4a4
I/DEBUG (11781): d30 bef375cbdb605373 d31 3f8b5c41074afda1
I/DEBUG (11781): scr 80000093
I/DEBUG (11781):
I/DEBUG (11781): backtrace:
I/DEBUG (11781): #00 pc 00367a4e /data/app-lib/de.tum.ei.lmt.inmaps3d-1/libInMapsJNI.so (Simulator::run()+69)
I/DEBUG (11781): #01 pc 0051b600 /data/app-lib/de.tum.ei.lmt.inmaps3d-1/libInMapsJNI.so
I/DEBUG (11781):
I/DEBUG (11781): stack:
I/DEBUG (11781): 66da3e20 83a88000
I/DEBUG (11781): 66da3e24 02ed263d
I/DEBUG (11781): 66da3e28 83a88000
I/DEBUG (11781): 66da3e2c 02ed263d
I/DEBUG (11781): 66da3e30 61f05dd3
I/DEBUG (11781): 66da3e34 0004f4cf
I/DEBUG (11781): 66da3e38 532719d5 /dev/ashmem/dalvik-mark-stack (deleted)
I/DEBUG (11781): 66da3e3c 176a6e38
I/DEBUG (11781): 66da3e40 61c0ee99 /data/app-lib/de.tum.ei.lmt.inmaps3d-1/libInMapsJNI.so
I/DEBUG (11781): 66da3e44 001e8480
I/DEBUG (11781): 66da3e48 00000000
I/DEBUG (11781): 66da3e4c 00000000
I/DEBUG (11781): 66da3e50 40490000 /system/lib/libskia.so (GrGLCaps::initStencilFormats(GrGLContextInfo const&)+808)
I/DEBUG (11781): 66da3e54 62055ab0
I/DEBUG (11781): 66da3e58 df0027ad
I/DEBUG (11781): 66da3e5c 00000000
I/DEBUG (11781): #00 66da3e60 001e8480
I/DEBUG (11781): 66da3e64 00000000
I/DEBUG (11781): 66da3e68 00000000
I/DEBUG (11781): 66da3e6c 00000000
I/DEBUG (11781): 66da3e70 00000000
I/DEBUG (11781): 66da3e74 00000000
I/DEBUG (11781): 66da3e78 00000000
I/DEBUG (11781): 66da3e7c 00000000
I/DEBUG (11781): 66da3e80 3f800000
I/DEBUG (11781): 66da3e84 40000000
I/DEBUG (11781): 66da3e88 40400000 /system/lib/libskia.so
I/DEBUG (11781): 66da3e8c 00000000
I/DEBUG (11781): 66da3e90 00000000
I/DEBUG (11781): 66da3e94 40490000 /system/lib/libskia.so (GrGLCaps::initStencilFormats(GrGLContextInfo const&)+808)
I/DEBUG (11781): 66da3e98 00000000
I/DEBUG (11781): 66da3e9c 16c16c17
Your InMapsEngine reference is not initialized or do you set it up outside of the class constructor ?
InMapsEngine & engine_;
You could use member object instead
InMapsEngine engine_;
... or set your reference before the thread calls it.
It's hard to tell from your stacktrace exactly what is going wrong, but it could be that you have multiple threads trying to access your shared engine resource at the same time.
One way to do this would be to use a mutex and condition variable to signal to your threads when your engine resource is available to them.:
try{
boost::mutex::scoped_lock lock(engine_mutex);
m_condition.wait(lock);
engine_.updateLocationEstimate(estimate);
m_condition.notify_one();
}
catch (boost::thread_interrupted&) {
return;
}
boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
Though you may want to use a regular lock instead if you want to include your sleep in the try block. Just remember to unlock.