value-of select in xslt 2.0 - xslt-2.0

I am using xslt 2.0.
I am using value-of select and getting a concatenated string returned because of duplicate elements. I tried preceding-sibling and generate-id and neither would remove the second part of the string. How can I accomplish this?
output
2 11 Kenneth Street 3755 Peachtree Road NE (bold section from second element to be removed)
<xsl:value-of select="wd:Personal_Data/wd:Contact_Data/wd:Address_Data/wd:Address_Line_Data[#wd:Type='ADDRESS_LINE_1']"/>
xml
<wd:Contact_Data>
<wd:Address_Data wd:Effective_Date="2000-01-01-08:00" wd:Address_Format_Type="Extended" wd:Formatted_Address="Av Cmte Júlio Moura, 900&#xa;Barra de Tijuca&#xa;Rio de Janeiro- RJ&#xa;22621-252&#xa;Brazil" wd:Defaulted_Business_Site_Address="0">
<wd:Country_Reference wd:Descriptor="Brazil">
<wd:ID wd:type="WID">1a29bb1357b240ab99a2fa755cc87c0e</wd:ID>
<wd:ID wd:type="ISO_3166-1_Alpha-2_Code">BR</wd:ID>
<wd:ID wd:type="ISO_3166-1_Alpha-3_Code">BRA</wd:ID>
<wd:ID wd:type="ISO_3166-1_Numeric-3_Code">76</wd:ID>
</wd:Country_Reference>
<wd:Last_Modified>2009-06-06T20:07:49.246-07:00</wd:Last_Modified>
<wd:Address_Line_Data wd:Type="ADDRESS_LINE_1" wd:Descriptor="Street Name">Av Cmte Júlio Moura</wd:Address_Line_Data>
<wd:Address_Line_Data wd:Type="ADDRESS_LINE_3" wd:Descriptor="House Number">900</wd:Address_Line_Data>
<wd:Municipality>Rio de Janeiro</wd:Municipality>
<wd:Submunicipality_Data>Barra de Tijuca</wd:Submunicipality_Data>
<wd:Country_Region_Reference wd:Descriptor="Rio de Janeiro">
<wd:ID wd:type="WID">e88c3d7cdb2b4a8b8120ede0b16e2186</wd:ID>
<wd:ID wd:type="Country_Region_ID">BRA-RJ</wd:ID>
</wd:Country_Region_Reference>
<wd:Postal_Code>22621-252</wd:Postal_Code>
<wd:Usage_Data wd:Public="0">
<wd:Type_Data wd:Primary="1">
<wd:Type_Reference wd:Descriptor="Home">
<wd:ID wd:type="WID">836cf00ef5974ac08b786079866c946f</wd:ID>
<wd:ID wd:type="Communication_Usage_Type_ID">HOME</wd:ID>
</wd:Type_Reference>
</wd:Type_Data>
<wd:Use_For_Reference wd:Descriptor="Street Address">
<wd:ID wd:type="WID">f785430145674364a613cd56086942c4</wd:ID>
<wd:ID wd:type="Communication_Usage_Behavior_ID">STREET</wd:ID>
</wd:Use_For_Reference>
<wd:Use_For_Reference wd:Descriptor="Mailing">
<wd:ID wd:type="WID">9385649a0c4b4ddea7fb0d823c2f1bcd</wd:ID>
<wd:ID wd:type="Communication_Usage_Behavior_ID">MAILING</wd:ID>
</wd:Use_For_Reference>
</wd:Usage_Data>
</wd:Address_Data>
<wd:Address_Data wd:Effective_Date="2000-01-01-08:00" wd:Address_Format_Type="Basic" wd:Formatted_Address="3755 Peachtree Road NE&#xa;Atlanta, GA 30305&#xa;United States of America" wd:Defaulted_Business_Site_Address="1">
<wd:Country_Reference wd:Descriptor="United States of America">
<wd:ID wd:type="WID">bc33aa3152ec42d4995f4791a106ed09</wd:ID>
<wd:ID wd:type="ISO_3166-1_Alpha-2_Code">US</wd:ID>
<wd:ID wd:type="ISO_3166-1_Alpha-3_Code">USA</wd:ID>
<wd:ID wd:type="ISO_3166-1_Numeric-3_Code">840</wd:ID>
</wd:Country_Reference>
<wd:Last_Modified>2011-06-20T13:54:02.466-07:00</wd:Last_Modified>
<wd:Address_Line_Data wd:Type="ADDRESS_LINE_1" wd:Descriptor="Address Line 1">3755 Peachtree Road NE</wd:Address_Line_Data>

If you only want to output the first selected element then use <xsl:value-of select="(wd:Personal_Data/wd:Contact_Data/wd:Address_Data/wd:Address_Line_Data[#wd:Type='ADDRESS_LINE_1'])[1]"/>.
Or based on the input you have shown I think <xsl:value-of select="wd:Personal_Data/wd:Contact_Data/wd:Address_Data[1]/wd:Address_Line_Data[#wd:Type='ADDRESS_LINE_1']"/> should also work.
Also note that you can use version="1.0" on your stylesheet with an XSLT 2.0 processor to indicate you are moving XSLT 1.0 to 2.0 but currently want XSLT 1.0 backwards compatible processing (such as outputting only the first selected node with xsl:value-of). That way you can adapt your code gradually.

Related

xslt2: sequence of attribute nodes

This is not really a question but an astonishing xslt2 experience that I like to share.
Take the snippet (subtract one set from another)
<xsl:variable name="v" as="node()*">
<e a="a"/>
<e a="b"/>
<e a="c"/>
<e a="d"/>
</xsl:variable>
<xsl:message select="$v/#a[not(.=('b','c'))]"/>
<ee>
<xsl:sequence select="$v/#a[not(.=('b','c'))]"/>
</ee>
What should I expect to get?
I expected a d at the console and
<ee>a d</ee>
at the output.
What I got is
<?attribute name="a" value="a"?><?attribute name="a" value="d"?>
at the console and
<ee a="d"/>
at the output. I should have known to take $v/#a as a sequence of attribute nodes to predict the output.
In order to get what I wanted, I had to convert the sequence of attributes to a sequence of strings like:
<xsl:variable name="w" select="$v/#a[not(.=('b','c'))]" as="xs:string*"/>
Questions:
Is there any use of sequences of attributes (or is it just an interesting effect of the node set concept)?
If so, would I be able to enter statically a sequence of attributes like I am able to enter a sequence of strings: ('a','b','c','d')
Is there any inline syntax to convert a sequence of attributes to a sequence of strings? (In order to achieve the same result omitting the variable w)
It seems to be an elegant way for creating attributes using xsl:sequence. Or would that be a misuse of xslt2, not covered by the standard?
As for "Is there any inline syntax to convert a sequence of attributes to a sequence of strings", you can simply add a step $v/#a[not(.=('b','c'))]/string(). Or use a for $a in $v/#a[not(.=('b','c'))] return string($a) and of course in XPath 3 $v/#a[not(.=('b','c'))]!string().
I am not sure what the question about the "use of sequences of attributes" is about, in particular as it then mentions the XPath 1 concept of node sets. If you want to write a function or template to return some original attribute nodes from an input then xsl:sequence allows that. Of course, inside a sequence constructor like the contents of an element, if you look at 10) in https://www.w3.org/TR/xslt20/#constructing-complex-content, in the end a copy of the attribute is created.
As for creating a sequence of attributes, you can't do that in XPath which can't create new nodes, you can however do that in XSLT:
<xsl:variable name="att-sequence" as="attribute()*">
<xsl:attribute name="a" select="1"/>
<xsl:attribute name="b" select="2"/>
<xsl:attribute name="c" select="3"/>
</xsl:variable>
then you can use it elsewhere, as in
<xsl:template match="/*">
<xsl:copy>
<element>
<xsl:sequence select="$att-sequence"/>
</element>
<element>
<xsl:value-of select="$att-sequence"/>
</element>
</xsl:copy>
</xsl:template>
and will get
<example>
<element a="1" b="2" c="3"/>
<element>1 2 3</element>
</example>
http://xsltfiddle.liberty-development.net/jyyiVhg
XQuery has a more compact syntax and in contrast to XPath allows expressions to create new nodes:
let $att-sequence as attribute()* := (attribute a {1}, attribute b {2}, attribute c {3})
return
<example>
<element>{$att-sequence}</element>
<element>{data($att-sequence)}</element>
</example>
http://xqueryfiddle.liberty-development.net/948Fn56

XSLT unparsed text replacement or formatting for bold or font change

I want the unparsed text to be formatted for bold characters or increase font-size based on the tag the non-working example here is for replace the searched text with bold characters Example string (this post strips all the html bold characters):
'test how to when bold when there is more than one place to bold'
Can you please advice what is wrong here
<xsl:variable name="tcline" select="unparsed-text('generic_tc.txt','UTF-8')"/>
<xsl:analyze-string select="$tcline" regex="\'<b>'(.*?)\'<b>'">
<xsl:matching-substring>
<xsl:value-of select="replace($tcline,'\"<b>"(.*?)\"<b>"','<em>$1\/em/g;')"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
Also what will be a good place to test xsl when your template is in server somewhere?

How the "as" attribute of xsl:template affects the result of xsl:apply-templates

Given this source document:
<things>
<thing><duck>Eider</duck></thing>
<thing><duck>Mallard</duck></thing>
<thing><duck>Muscovy</duck></thing>
</things>
I require the following output
Fat Eider, Fat Mallard, Fat Muscovy
which I can indeed get with this XSL transform:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of separator=", ">
<xsl:apply-templates select="//duck"/>
</xsl:value-of>
</xsl:template>
<xsl:template match="duck" as="xs:string">
<xsl:value-of select="concat('Fat ', .)"/>
</xsl:template>
</xsl:stylesheet>
However, I have three questions:
Question 1. (specific)
If I remove as="xs:string" from the duck template, I get the following output:
Fat EiderFat MallardFat Muscovy
Why? My understanding is that in XSLT 2.0 the result of xsl:apply-templates is always a sequence, and that xsl:value-of inserts its separator between the items in the sequence. So why does the sequence seem to "collapse" when the template has no as attribute? Bonus points for pointing me towards appropriate pages of Michael Kay's excellent "XSLT 2.0 and XPath 2.0, 4th Edition" book.
Question 2. (vague!)
As a novice user of XSLT, it seems to me that there are probably many ways to solve this problem. Can you put forward a good solution that takes a different approach? How do you choose between approaches?
Question 3.
Debugging. Can you recommend how to dump out intermediate results that would indicate the difference between the presence and the absence of the as attribute to the template?
See http://www.w3.org/TR/xslt20/#value-of which says
The string value of the new text node may be defined either by using
the select attribute, or by the sequence constructor (see 5.7 Sequence
Constructors) that forms the content of the xsl:value-of element.
These are mutually exclusive, and one of them must be present. The way
in which the value is constructed is specified in 5.7.2 Constructing
Simple Content.
So we need to look at http://www.w3.org/TR/xslt20/#constructing-simple-content and that says "2. Adjacent text nodes in the sequence are merged into a single text node.". So that is what is happening without the as="xs:string", the sequence constructor inside the xsl:value-of creates adjacent text nodes which are merged into a single text node. If you have as="xs:string" or did <xsl:sequence select="concat('Fat ', .)"/> the sequence constructor is of a sequence of primitive string values.

XML Transform with XSLT

I have a XML file like below:
<NOP>A focus on individual exhibitors is essential, though, in order to
understand how these figures influenced American (and global) culture and
how audiences were attracted to movies and movie theaters. Charles Musser
writes in his examination of Lyman Howe’s career that “a focus on
exhibition lends itself to industrial history precisely because it must
address the economic basis of the motion picture industry—the showman’s
ability to bring patrons through the front door.â€<ENREF>1</ENREF> In order
to understand the artistic and managerial influences of showmen like Samuel
Lionel Rothafel (“Roxyâ€) and Sidney Patrick Grauman, one must analyze
their construction of stardom, their ethnic heritage and cultural background,
their facility with music, theater, film, and other performing arts, and the
ways in which they motivated patrons to enter their “front door.â€
</NOP>
and I'm using the below XSLT with XML spy but it's not working for 'ENREF'. Any help
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="NOP">
<div class="no-indent"><span><xsl:value-of select="."/></span></div>
</xsl:template>
<xsl:template match="ENREF">
<small>
<sup>
<xsl:element name="a">
<xsl:attribute name="id">enref-<xsl:value-of select="."/></xsl:attribute>
<xsl:attribute name="href">#fn<xsl:value-of select="."/></xsl:attribute>
<xsl:value-of select="."/>
</xsl:element>
</sup>
</small>
</xsl:template>
</xsl:stylesheet>
It does not suffice to write a template matching a certain element, you also need to ensure the element is processed. You have not shown us the result you want so I have to guess what you want to achieve but for a start try changing
<xsl:template match="NOP">
<div class="no-indent"><span><xsl:value-of select="."/></span></div>
</xsl:template>
to
<xsl:template match="NOP">
<div class="no-indent"><span><xsl:apply-templates/></span></div>
</xsl:template>
That way the child nodes of the NOP element are processed, either by the built-in templates (which ensure with <xsl:apply-templates/> that the processing is kept up for grandchildren and further descendants) or by your templates (like the one for the ENREF element).

Dual-line bilingual paragraph in LaTeX [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
An interlinear gloss can be used to layout a translation of a document.
http://en.wikipedia.org/wiki/Interlinear_gloss
Usually this is done word-by-word or morpheme-by-morpheme. However, I would like to do this in a different way, translating entire paragraphs at a time. The following link and image is an example of what I want done, though I want to do it for a different text which is larger.
http://www.optimnem.co.uk/learning/spanish/three-little-pigs.php
For now I am not interested in taking into account the order of words or phrases that change order between languages. That is, I don't mind if the words in the paragraph are not aligned or if the length of one paragraph is much longer than the other, causing an overhanging line.
As far as I can tell, the following packages do not meet my needs:
covingtn.sty
cgloss4e.sty
gb4e.sty
lingmacros.sty - shortex
Here is the english version:
In the heart of the forest lived three little pigs who were brothers. The wolf always was chasing them in order to eat them. In order to escape the wolf, the pigs decided to make a house each. The smallest made his from straw, to finish first and go out to play. The middle one constructed a cottage from wood. Seeing that his little brother had finished already, he hurried to go and play with him. The oldest worked on his house of brick. 'You'll soon see what the wolf does with your houses,' he scolded his brothers but they were having a great time.
Here is the spanish version:
En el corazón del bosque vivían tres cerditos que eran hermanos. El lobo siempre andaba persiguiéndoles para comérselos. Para escapar del lobo, los cerditos decidieron hacerse una casa. El pequeño la hizo de paja, para acabar antes y poder irse a jugar. El mediano construyó una casita de madera. Al ver que su hermano perqueño había terminado ya, se dio prisa para irse a jugar con él. El mayor trabajaba en su casa de ladrillo. - Ya veréis lo que hace el lobo con vuestras casas - riñó a sus hermanos mientras éstos se lo pasaban en grande.
I don't want to do it manually like this:
\documentclass{article}
\usepackage[margin=1in, paperwidth=8.5in, paperheight=11in]{geometry}
\usepackage[utf8]{inputenc}
\usepackage{url}
\begin{document}
\noindent
\url{http://www.optimnem.co.uk/learning/spanish/three-little-pigs.php}\\
\\
\indent
En el corazón del bosque vivían tres cerditos que eran hermanos. El lobo siempre\\
\indent
In the heart of the forest lived three little pigs who were brothers. The wolf always\\
\\
%
andaba persiguiéndoles para comérselos. Para escapar del lobo, los cerditos decidieron\\
was chasing them in order to eat them. In order to escape the wolf, the pigs decided to\\
\\
%
hacerse una casa. El pequeño la hizo de paja, para acabar antes y poder irse a jugar.\\
make a house each. The smallest made his from straw, to finish first and go out to play.\\
\\
%
El mediano construyó una casita de madera. Al ver que su hermano perqueño había\\
The middle one constructed a cottage from wood. Seeing that his little brother had\\
\\
%
terminado ya, se dio prisa para irse a jugar con él. El mayor trabajaba en su casa de\\
finished already, he hurried to go and play with him. The oldest worked on his house of\\
\\
%
ladrillo. - Ya veréis lo que hace el lobo con vuestras casas - riñó a sus hermanos\\
brick. 'You'll soon see what the wolf does with your houses,' he scolded his brothers\\
\\
%
mientras éstos se lo pasaban en grande.\\
but they were having a great time.\\
\\
\end{document}\\
I would like to use a package or a macro to automatically have the english and spanish texts interspersed with line breaks when the end of the line has been reached for each. How can I layout this simple dual-line biligual paragraph in Latex in a more automated way (without manually adding line breaks)?
The following hack may help you achieve your goal. It's based on the idea of a zero-height minipage to overlap two triple-spaced minipages.
I'll use placeholders for the English and Spanish text (\english and \spanish respectively). Also, be sure to include the setspace package:
\usepackage{setspace}
\def\english{In the heart of the forest lived three little pigs who were brothers. The wolf always was chasing them in order to eat them. In order to escape the wolf, the pigs decided to make a house each. The smallest made his from straw, to finish first and go out to play. The middle one constructed a cottage from wood. Seeing that his little brother had finished already, he hurried to go and play with him. The oldest worked on his house of brick. 'You'll soon see what the wolf does with your houses,' he scolded his brothers but they were having a great time.}
\def\spanish{En el corazón del bosque vivían tres cerditos que eran hermanos. El lobo siempre andaba persiguiéndoles para comérselos. Para escapar del lobo, los cerditos decidieron hacerse una casa. El pequeño la hizo de paja, para acabar antes y poder irse a jugar. El mediano construyó una casita de madera. Al ver que su hermano perqueño había terminado ya, se dio prisa para irse a jugar con él. El mayor trabajaba en su casa de ladrillo. - Ya veréis lo que hace el lobo con vuestras casas - riñó a sus hermanos mientras éstos se lo pasaban en grande.}
By giving the top block a height of 0pt we allow for the next minipage to overlap it.
\begin{minipage}[t][0pt]{\linewidth}
\setstretch{3}
\english
\end{minipage}
\begin{minipage}[t]{\linewidth}
\setstretch{3}
\spanish
\end{minipage}
The primary One of the problems with this idea is that if the zero-height section is longer than the regular section, then you'll have some lingering overlapping text to deal with. (Edit: This problem is addressed in the comment below, note that line-breaks will also be a serious drawback to this idea.)
The result (in part):
I don't think there is a package to do what you want, but it is possible to implement this yourself using \vsplit, which is well documented in Tex by Topic (availble for free download, or in the dead-tree edition via Lulu). The basic idea is
You define two vboxes, one for the English, one for the Spanish, and you want to take out the contents one line at a time. Call these vboxes \ENbox and \ESbox;
You need to determine the correct vertical dimension to use: this might be \lineheight, or you might need a different value, you will have to experiment. Assuming \lineheight is right ...
... then you can get the next line of English using \setbox\nextline=\vsplit\ENbox to \lineheight, which you can output using \unvbox\ENbox, then likewise the next line from \ESbox, then some vertical space for the intergloss gap;
Then you need to test the loop, which you can do by querying the vertical heights, using \ht, of \ENbox and \ESbox. This bit will be fiddly.
All-in-all, this will be somewhat tricky coding: good luck, and don't hesitate to ask questions here if you run into difficulties.
Postscript This is obviously much more work than Geoff's much simpler solution, which for some reason I hadn't seen when I wrote this, but it should be more flexible if you want to fiddle with it.
If you want to interlace Spanish and English paragraphs, and have them line up approximately correctly, then what you want is to write your translations word-by-word (or several words by several words), and use a gloss package that can wrap long sentences. I've done this before using gloss.sty. An example of its use(the goal was to gloss each word with its part of speech):
\gloss Both knowledge and wisdom extend man's reach. Knowledge led to
cjc nn0 cjc nn0 vvb {nn0 pos} {nn0 pun} nn0 vvd prp
\gloss computers, wisdom to chopsticks. Unfortunately our association is
{nn2 pun} nn0 prp {nn2 pun} av0 dps nn1 vbz
\gloss overinvolved with the former. The latter will have to wait for a
ad0 prp at0 {nn0 pun} at0 nn0 vm0 vhb to0 vvb avp at0
\gloss more sublime day.
av0 aj0 {nn1 pun}
\unhbox\gline
The package lines things up words from the first language with words from the second "language" using spaces. To line up multiple words in one language with a single word (or multiple words) from the other language, use braces to group the multiple words. Though the lines here are interlaced, this is just for my editing convenence. You could write really long lines if you wanted to, and the gloss algorithm will wrap them properly.
I've also used a two-column paragraph-by-paragraph approach using the parallel package.
put an extra line break in between each set of lines:
%
andaba persiguiéndoles para comérselos. Para escapar del lobo, los cerditos decidieron
was chasing them in order to eat them. In order to escape the wolf, the pigs decided to
%

Resources