I want to add the tag inside value as num value and removing the section roman numbers and symbol inside the title tag
My Input XML File:
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="d102e3" xml:lang="en-US">
<title outputclass="Chapter_Title">Base Food</title>
<subsection id="d102e11" xml:lang="en-US" outputclass="Heading_1">
<title> § I Nothing</title>
<body>
<p outputclass="Body_Text">1Y The Act also states that the may undertake a review of the definition of the term.</p>
</body>
</subsection>
<subsection id="d102e20" xml:lang="en-US" outputclass="Heading_2">
<title> § II Proposed Amendments: “Accredited Natural Person”</title>
<body>
</subsection>
<p outputclass="Body_Text">1Y The Act also states that the may undertake a review of the definition of the term.</p>
</body>
</chapter>
My XSLT Coding is
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"></xsl:output>
<xsl:template match="/">
<xsl:apply-templates></xsl:apply-templates>
</xsl:template>
<xsl:template match="*[contains(#class,' chapter/chapter ')]">
<chapter>
<xsl:apply-templates/>
</chapter>
</xsl:template>
<xsl:template match="subsection">
<section level="sect{format-number(count(preceding::subsection)+1,'0000')}" num="I" number-type="manual">
<xsl:apply-templates/>
</section>
</xsl:template>
<xsl:template match="*[contains(#class,' topic/p ')]">
<para>
<xsl:apply-templates/>
</para>
</xsl:template>
<xsl:template match="*[contains(#class,' topic/title ')]">
<title>
<xsl:apply-templates/>
</title>
</xsl:template>
</xsl:stylesheet>
</xsl:stylesheet>
I am getting output as
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<chapter>
<title>Base Food</title>
<section level="sect0001" num="I" number-type="manual">
<title> § I Nothing</title>
<para>1Y The Act also states that the may undertake a review of the definition of the term.</para>
</section>
<section level="sect0001" num="I" number-type="manual">
<title> § II Proposed Amendments: “Accredited Natural Person”</title>
<para>1Y The Act also states that the may undertake a review of the definition of the term.</para>
</section>
</chapter>
but i want output in side title tag roman number format in 'num' attributes and remove the number and symbol '§ I' inside title tag:
output needed as
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<chapter>
<title>Base Food</title>
<section level="sect1" num="§ I" number-type="manual">
<title>Nothing</title>
<para>1Y The Act also states that the may undertake a review of the definition of the term.</para>
</section>
<section level="sect2" num="§ II" number-type="manual">
<title>Proposed Amendments: “Accredited Natural Person”</title>
<para>1Y The Act also states that the may undertake a review of the definition of the term.</para>
</section>
</chapter>
Please assist me.
Thanks in Advance
Related
XML
<books>
<book title="XML Today" author="David Perry" release="2016"/>
<book title="XML and Microsoft" author="David Perry" release="2015"/>
<book title="XML Productivity" author="Jim Kim" release="2015"/>
</books>
The following XSL code iterates through all books by David Perry.
XSL
<xsl:key name="title-search" match="book" use="#author"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="#title"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
HTML output
<HTML>
<BODY>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
</BODY>
</HTML>
Now I would like to iterate not only through all books by David Perry but through all books by any author.
How would a corresponding outer loop look like?
Or in other words: How do I iterate through all values of my title-search key.
The output should be something like this:
<HTML>
<BODY>
<H1>David Perry</H1>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
<H1>Jim Kim</H1>
<DIV>XML Productivity</DIV>
</BODY>
</HTML>
This should do the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="title-search" match="book" use="#author"/>
<xsl:template match="/books">
<HTML>
<BODY>
<xsl:apply-templates select="book" />
</BODY>
</HTML>
</xsl:template>
<xsl:template match="book">
<xsl:variable name="author" select="#author" />
<xsl:if test="generate-id(.) = generate-id(key('title-search', $author)[1])">
<H1><xsl:value-of select="#author" /></H1>
<xsl:apply-templates select="//book[#author = $author]" mode="titles"/>
</xsl:if>
</xsl:template>
<xsl:template match="book" mode="titles">
<DIV>
<xsl:value-of select="#title"/>
</DIV>
</xsl:template>
</xsl:stylesheet>
It uses a technique called Muenchian grouping. Each element in an XML document implicitly has a unique ID assigned to it by the XSLT processor (it can also be explicitly assigned with the id attribute in the document itself). This part:
generate-id(.) = generate-id(key('title-search', $author)[1])
basically tests if the ID of the current book element is the same as that of the first book element with the same author. The variable $author is taken from the current book, The key is used to look up the <book> elements with that same author, the [1] predicate takes the first one. As a result, the <H1> is only generated for the first occurrence of that specific author, and in that same if element we're then applying the template for listing the books of that author. The mode is used to avoid a clash between these templates. There's no doubt a solution that doesn't use modes, but this works too. You could also do a lot of this with <xsl:for-each> but I made separate templates because XSLT is declarative and works best when treating it as such.
Grouping is a lot easier in XSLT 2, but when stuck with XSLT 1, the Muenchian grouping technique often provides a solution once you grok it.
Try this:
XSLT2:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each-group select="books/book" group-by="#author">
<H1><xsl:value-of select="current-grouping-key()"/></H1>
<xsl:for-each select="current-group()">
<DIV><xsl:value-of select="#title"/></DIV>
</xsl:for-each>
</xsl:for-each-group>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
Given the following xml inputs:
file1:
<?xml version="1.0" encoding="UTF-8"?>
<File1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<code code="file1_code" displayName="file1_display" codeSystem="file1_cs" codeSystemName="file1_csn"/>
<title>Title of file1</title>
<component typeCode="COMP">
<structuredBody classCode="DOCBODY">
<component typeCode="COMP">
<section>
<templateId root="someRoot_file1" assigningAuthorityName="someAuhthority_file1"/>
<code code="file1-sec1_code" displayName="file1_sec1_display" codeSystem="file1_sec1_cs" codeSystemName="file1_sec1_csn"/>
<title>Tile of sec 1 from file1</title>
<text>
<content styleCode="Italics">
Text of sec 1 from file1
</content>
</text>
<entry> file 1 sec 1
</entry>
</section>
</component>
<component typeCode="COMP">
<section classCode="DOCSECT">
<code code="file1_sec2_code" codeSystem="file2_sec2_cs" displayName="file2_sec2_display" codeSystemName="file2_sec2_csn"/>
<title>Tile from sec 2 file 1</title>
<text>
<content styleCode="Italics">
Text from file1 sec 2
</content>
</text>
<entry typeCode="test"> file2 sec 2
</entry>
</section>
</component>
</structuredBody>
</component>
</File1>
file2:
<?xml version="1.0"?>
<A>
<title value="Title of file2"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>File 2 Text</p>
</div>
</text>
<section>
<code>
<coding>
<system value="sec 1 file2 sys"/>
<code value="sec 1 file 2 code"/>
<display value="sec 1 file 2 display"/>
</coding>
</code>
<title>Title of sec 1 file2</title>
<text>
<content styleCode="Italics">Section 1 Text
</content>
</text>
<entry>
<someEntry>
</someEntry>
</entry>
</section>
<section>
<code>
<coding>
<system value="sec 2 file2 sys"/>
<code value="sec 2 file 2 code"/>
<display value="sec 2 file 2 display"/>
</coding>
</code>
<title>Title of sec 2 file2</title>
<text>
<content styleCode="Italics">Section 2 file2 Text
</content>
</text>
<entry>
<someEntry> entry sec 2 file 2
</someEntry>
</entry>
</section>
</A>
and the following xslt:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:variable name="input" select="/" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<Bundle>
<id value="test"/>
<type value="document"/>
<entry>
<resource>
<xsl:apply-templates select="document('file2.xml')/*"/>
</resource>
</entry>
</Bundle>
</xsl:template>
<xsl:template match="text">
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the text from the stylesheet </p>
</div>
</text>
</xsl:template>
<xsl:template match="title">
<xsl:apply-templates select="$input/File1/title"/>
</xsl:template>
<xsl:template match="section[1]">
<xsl:apply-templates select="$input/File1/component/structuredBody/component/section"/>
</xsl:template>
<xsl:template match="section[2]"/>
<xsl:template match="File1/title">
<title>
<xsl:attribute name="value">
<xsl:value-of select="." />
</xsl:attribute>
</title>
</xsl:template>
<xsl:template match = "File1/component/structuredBody/component/section">
<section>
<xsl:apply-templates/>
</section>
</xsl:template>
</xsl:stylesheet>
And this is the output:
<?xml version="1.0" encoding="UTF-8"?>
<Bundle>
<id value="test"/>
<type value="document"/>
<entry>
<resource>
<A>
<title value="Title of file1"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the text from the stylesheet </p>
</div>
</text>
<section>
<templateId xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" root="someRoot_file1" assigningAuthorityName="someAuhthority_file1"/>
<code xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" code="file1-sec1_code" displayName="file1_sec1_display" codeSystem="file1_sec1_cs" codeSystemName="file1_sec1_csn"/>
<title value="Title of file1"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the text from the stylesheet </p>
</div>
</text>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</section>
<section>
<code xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" code="file1_sec2_code" codeSystem="file2_sec2_cs" displayName="file2_sec2_display" codeSystemName="file2_sec2_csn"/>
<title value="Title of file1"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the text from the stylesheet </p>
</div>
</text>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" typeCode="test"/>
</section>
</A>
</resource>
</entry>
</Bundle>
And this is the expected output:
<?xml version="1.0" encoding="UTF-8"?>
<Bundle>
<id value="test"/>
<type value="document"/>
<entry>
<resource>
<A>
<title value="Title of file1"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the text from the stylesheet </p>
</div>
</text>
<section>
<templateId xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" root="someRoot_file1" assigningAuthorityName="someAuhthority_file1"/>
<code xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" code="file1-sec1_code" displayName="file1_sec1_display" codeSystem="file1_sec1_cs" codeSystemName="file1_sec1_csn"/>
<title>Tile of sec 1 from file1</title>
<text>
<content styleCode="Italics">
Text of sec 1 from file1
</content>
</text>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</section>
<section>
<code xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" code="file1_sec2_code" codeSystem="file2_sec2_cs" displayName="file2_sec2_display" codeSystemName="file2_sec2_csn"/>
<title>Tile from sec 2 file 1</title>
<text>
<content styleCode="Italics">
Text from file1 sec 2
</content>
</text>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" typeCode="test"/>
</section>
</A>
</resource>
</entry>
</Bundle>
I have the following questions:
Why is the title in the section elements coming from the main title (i.e. File1/title) when the apply templates is within File1/component/structuredBody/component/section? I was expecting that the title of the section will be output, which is what is desired. Even more confusing is that it does indeed output the elements in the section like code, entry and so on but title and text (see q2 below) seems to be treated differently and I can't for the life of me understand why.
Same with text. Why is the text for section not being output?
Here is my presumably false understanding of the process:
We start with the <xsl:template match="/"> and create elements Bundle, id etc. and then using <xsl:apply-templates select="document('file2.xml')/*"/> we match the top element of file2 (A) and since we don't have a template matching it explicitly, the identity template is called, copies it and process its child elements, which are text, title and section. For each of these child elements, it looks for a matching template. it finds them and matches them.
For element section however, it matches only the first section element because of <xsl:template match="section[1]"> and then because of <xsl:apply-templates select="$input/File1/component/structuredBody/component/section"/> in the template, it looks for a template matching children of section in FIle1, which are code, text, title and templateId. It finds no such explicitly defined template, so calls the identity templates for them, copies and processes them till the end. At least that is my understanding of it.
Why is the title in the section elements coming from the main title
Because any time the processor is instructed to apply templates to a title, it looks for the best-matching template to apply, and finds this:
<xsl:template match="title">
<xsl:apply-templates select="$input/File1/title"/>
</xsl:template>
This changes the context to the title in File1.xml, and the best-matching template for this one is:
<xsl:template match="File1/title">
<title>
<xsl:attribute name="value">
<xsl:value-of select="." />
</xsl:attribute>
</title>
</xsl:template>
and that is the result you see.
Same with text. Why is the text for section not being output?
-- edited in response to the following clarification: --
When I say text I am talking about text elements only.
The original text element (child of section in File1.xml) is not being output because you have a specific template matching it and outputting something else instead:
<xsl:template match="text">
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the text from the stylesheet </p>
</div>
</text>
</xsl:template>
# michael.hor257k and #Michael Kay yeah, that was definitely the case, that I misunderstood how xsl:apply-templates works with regards to context . I thought because I called the xsl:apply-templates from within xsl:template match = "$input/File1/component/structuredBody/component/section"> that it will only look for match templates that match the children of section. In other words, I thought it will look for templates like “<xsl:template match=”File1/component/structuredBody/component/section/title"> but that is clearly not the case.
xsl:apply-templates simply looks for the children and then looks for a match template regardless of the context from which they were called. So, it will look for title or text template that matches and if it finds them, it will match them.
The easiest solution I could find that seems to solve the problem is to add a path to the title and text templates. In other words, instead of just <xsl:template match="text"> I should have <xsl:template match="A/text">. Same for title. This way, the xsl:apply-templates will not apply <xsl:template match="A/text"> as the title in section is not a child of A. So given that no matching explicit template is defined, the identity template will be applied and will output the title of section as desired.
I've the below XML.
<chapter num="1">
<section level="sect2">
<page>22</page>
</section>
<section level="sect3">
<page>23</page>
</section>
</chapter>
here I'm trying to get the first occurrence of <page>.
I'm using the below XSLT.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ntw="Number2Word.uri" exclude-result-prefixes="ntw">
<xsl:output method="html"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="ThisDocument" select="document('')"/>
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE html>]]></xsl:text>
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="chapter">
<section class="tr_chapter">
<xsl:value-of select="//page[1]/text()"/>
<div class="chapter">
</div>
</section>
</xsl:template>
</xsl:stylesheet>
but the output that I get all the page valyes printed. I only want the first one.
Current output.
<!DOCTYPE html>
<html>
<body>
<section class="tr_chapter">2223
<div class="chapter">
</div>
</section>
</body>
</html>
the page values are printed here after <section class="tr_chapter">, i want only 22 but I'm getting 2223
here I'm using //page[1]/text(), because I'm not sure that the page comes within the section, it is random.
please let me know how I can get only the first page value.
here is the transformation http://xsltransform.net/3NzcBsR
Try:
<xsl:value-of select="(//page)[1]"/>
http://xsltransform.net/3NzcBsR/1
Note that this gets the value of the first page element in the entire document.
If you want to search the contents of the chapter context element in your template for the first page descendant then use <xsl:value-of select="descendant::page[1]"/> or <xsl:value-of select="(.//page)[1]"/>.
I have a document with a specific attribute (myId) for which the value needs to be updated whenever its value is zero. The document looks like this
<?xml version="1.0" encoding="UTF-8"?><Summary>
<Section myId="0">
<Section myId="0">
<Para>...</Para>
</Section>
<Section myId="5">
<Para>...</Para>
</Section>
</Section>
</Summary>
I am using a template to match the attribute myId in order to set it to a unique ID passed from a calling program but I only want to match one of the attributes in the document. Any additional attributes with a value of zero will be updated by passing a different ID.
My template I'm using looks like this:
<xsl:template match = '#myId[.="0"]'>
<xsl:attribute name = "{name()}">
<xsl:value-of select = "$addValue"/>
</xsl:attribute>
</xsl:template>
The value addValue is a global parameter passed from the calling program.
I've searched for an answer for a good part of the day but I'm unable to have this template be applied only just once. The output replaces both myId values with the content of addValue.
I've tried to match with '#myId[."0"][1]' and I've tried to use the position() function to to match but my template is always applied to all myId attributes that are zero.
Is it possible to apply a matching template only once?
Is it possible to apply a matching template only once?
Yes:
Whether a template is applied or not depends on the xsl:apply-templates that causes the template to be selected for execution.
Additionaly, the match pattern can be specified in a way that guarantees that the template matches only one specific node in the document.
Here is what you can do:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNewIdValue" select="9999"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"Section
[#myId = 0
and
not((preceding::Section | ancestor::Section)
[#myId = 0]
)
]/#myId">
<xsl:attribute name="myId"><xsl:value-of select="$pNewIdValue"/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document:
<Summary>
<Section myId="0">
<Section myId="0">
<Para>...</Para>
</Section>
<Section myId="5">
<Para>...</Para>
</Section>
</Section>
</Summary>
the wanted, correct result is produced:
<Summary>
<Section myId="9999">
<Section myId="0">
<Para>...</Para>
</Section>
<Section myId="5">
<Para>...</Para>
</Section>
</Section>
</Summary>
I need to output from the XSL a static CDATA construct embedded in the XSL, not from the XML that I am transforming. For example...
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<!-- ================================================== -->
<xsl:template match="/">
<Document>
<text><![CDATA[
<b>static</b>
<br/><br/>
text
<br/><br/>
]]>
</text>
<xsl:apply-templates select="//tag"/>
</Document>
</xsl:template>
<!-- ================================================== -->
<xsl:template match="tag">
So on and so forth...
</xsl:template>
<!-- ================================================== -->
</xsl:stylesheet>
I want this to output...
<?xml version="1.0"?>
<Document>
<text><![CDATA[
<b>static</b>
<br/><br/>
text
<br/><br/>
]]>
</text>
So on and so forth...
</Document>
But what I get is...
<?xml version="1.0"?>
<Document>
<text>
<b>static</b>
<br/><br/>
text
<br/><br/>
</text>
So on and so forth...
</Document>
I've tried several combinations of escaping the text and entities, but none seem to work.
Use
<xsl:output cdata-section-elements="text" />
to enforce CDATA for certain elements (spec).
In any case, what you currently get is equivalent to a CDATA section and it should not bother you. (i.e.: If it's bothering you for optical reasons, then get over it. If it is bothering you for technical reasons, fix them.)