Still XSL Problems

  • Thread starter Buchleitner Martin
  • Start date
B

Buchleitner Martin

Hi!

I got another problem parsing my XML document:

<document>
<paragraph>
<style val=listing/>
<text>listing #1 text</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #1 text</text>
</paragraph>
<paragraph>
<style>text</style>
<text>some text between 2 listings</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #2 text</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #2 text</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #2 text</text>
</paragraph>
</document>

The output should look like:

<parsed>
<list>
<item>listing #1 text</item>
<item>listing #1 text</item>
<list>
<text>some text between 2 listings</text>
<list>
<item>listing #2 text</item>
<item>listing #2 text</item>
<item>listing #2 text</item>
<list>
</parsed>


My idea to get this result was:

<xsl:template match="text">
<xsl:value-of select="."/>
</xsl:template>

<xsl:template match="paragaph">
<xsl:if text="style[@val='listing'>
<list>
<item><xsl:apply-templates select="text"></item>

<xsl:for-each
select="following-sibling::paragraph/style[@val='listing']">
<item><xsl:apply-templates select="text"></item>
</xsl:for-each>
</list>
</xsl:if>
</xsl:template>
<xsl:template match="document">
<xsl:apply-templates select="paragraph"/>
</xsl:template>


But i was wrong - i get a document like:

<parsed>
<list>
<item>listing #1 text</item>
<item>listing #1 text</item>
<list>
<list>
<item>listing #1 text</item>
<list>
<text>some text between 2 listings</text>
<list>
<item>listing #2 text</item>
<item>listing #2 text</item>
<item>listing #2 text</item>
<list>
<list>
<item>listing #2 text</item>
<item>listing #2 text</item>
<list>
<list>
<item>listing #2 text</item>
</list>
</parsed>



How may i change my XSL to remove the repeated entries?
Can i modify the position in the paragraph-template?
Any ideas?


TIA, Martin
 
M

Marrow

Hi Martin,

At the moment your XML is not well-formed... <style val=listing/> is not
well-formed because the attribute value is not enclosed in quotes. As this
is inconsistent with <style>text</style> part perhaps your XML looks more
like...

== XML =================================================
<document>
<paragraph>
<style>listing</style>
<text>listing #1 text</text>
</paragraph>
<paragraph>
<style>listing</style>
<text>listing #1 text</text>
</paragraph>
<paragraph>
<style>text</style>
<text>some text between 2 listings</text>
</paragraph>
<paragraph>
<style>listing</style>
<text>listing #2 text</text>
</paragraph>
<paragraph>
<style>listing</style>
<text>listing #2 text</text>
</paragraph>
<paragraph>
<style>listing</style>
<text>listing #2 text</text>
</paragraph>
</document>
== end of XML ==========================================

You are really needing to 'group' the <paragraph> elements by when the
<style> value changes. In which case something like...

== XSL1 ================================================
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="xml" indent="yes"/>
<xsl:key name="kNonEqFollow" match="paragraph"
use="generate-id(following-sibling::paragraph[style != current()/style])"/>
<xsl:template match="document">
<parsed>
<xsl:apply-templates select="paragraph[not(preceding-sibling::paragraph)
or style != preceding-sibling::paragraph[1]/style]"/>
</parsed>
</xsl:template>

<xsl:template match="paragraph[style = 'listing']">
<!-- find the first following with a different <style> -->
<xsl:variable name="non-eq"
select="generate-id(following-sibling::paragraph[style !=
current()/style])"/>
<list>
<xsl:for-each select=". | key('kNonEqFollow',$non-eq)">
<item>
<xsl:value-of select="text"/>
</item>
</xsl:for-each>
</list>
</xsl:template>

<xsl:template match="paragraph[style = 'text']">
<!-- find the first following with a different <style> -->
<xsl:variable name="non-eq"
select="generate-id(following-sibling::paragraph[style !=
current()/style])"/>
<xsl:copy-of select="(. | key('kNonEqFollow',$non-eq))/text"/>
</xsl:template>

</xsl:stylesheet>
== end of XSL1 =========================================

However, if you are using MSXML 3.0 or MSXML 4.0 (pre SP2) then that
stylesheet will not work correctly due to a bug with current() in keys. An
alternative would be...

== XSL2 ================================================
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="xml" indent="yes"/>
<xsl:template match="document">
<parsed>
<xsl:apply-templates select="paragraph[not(preceding-sibling::paragraph)
or style != preceding-sibling::paragraph[1]/style]"/>
</parsed>
</xsl:template>

<xsl:template match="paragraph[style = 'listing']">
<!-- find how many non-equal items follow this one -->
<xsl:variable name="count-non-eq"
select="count(following-sibling::paragraph[style != current()/style])"/>
<list>
<xsl:for-each select=". | following-sibling::paragraph[style =
current()/style and count(following-sibling::paragraph[style !=
current()/style]) = $count-non-eq]">
<item>
<xsl:value-of select="text"/>
</item>
</xsl:for-each>
</list>
</xsl:template>

<xsl:template match="paragraph[style = 'text']">
<!-- find how many non-equal items follow this one -->
<xsl:variable name="count-non-eq"
select="count(following-sibling::paragraph[style != current()/style])"/>
<xsl:copy-of select="(. | following-sibling::paragraph[style =
current()/style and count(following-sibling::paragraph[style !=
current()/style]) = $count-non-eq])/text"/>
</xsl:template>

</xsl:stylesheet>
== end of XSL2 =========================================

Hope this helps
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator

Buchleitner Martin said:
Hi!

I got another problem parsing my XML document:

<document>
<paragraph>
<style val=listing/>
<text>listing #1 text</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #1 text</text>
</paragraph>
<paragraph>
<style>text</style>
<text>some text between 2 listings</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #2 text</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #2 text</text>
</paragraph>
<paragraph>
<style val=listing/>
<text>listing #2 text</text>
</paragraph>
</document>

The output should look like:

<parsed>
<list>
<item>listing #1 text</item>
<item>listing #1 text</item>
<list>
<text>some text between 2 listings</text>
<list>
<item>listing #2 text</item>
<item>listing #2 text</item>
<item>listing #2 text</item>
<list>
</parsed>


My idea to get this result was:

<xsl:template match="text">
<xsl:value-of select="."/>
</xsl:template>

<xsl:template match="paragaph">
<xsl:if text="style[@val='listing'>
<list>
<item><xsl:apply-templates select="text"></item>

<xsl:for-each
select="following-sibling::paragraph/style[@val='listing']">
<item><xsl:apply-templates select="text"></item>
</xsl:for-each>
</list>
</xsl:if>
</xsl:template>
<xsl:template match="document">
<xsl:apply-templates select="paragraph"/>
</xsl:template>


But i was wrong - i get a document like:

<parsed>
<list>
<item>listing #1 text</item>
<item>listing #1 text</item>
<list>
<list>
<item>listing #1 text</item>
<list>
<text>some text between 2 listings</text>
<list>
<item>listing #2 text</item>
<item>listing #2 text</item>
<item>listing #2 text</item>
<list>
<list>
<item>listing #2 text</item>
<item>listing #2 text</item>
<list>
<list>
<item>listing #2 text</item>
</list>
</parsed>



How may i change my XSL to remove the repeated entries?
Can i modify the position in the paragraph-template?
Any ideas?


TIA, Martin
 
B

Buchleitner Martin

On Mon, 7 Jul 2003 11:49:24 +0100, "Marrow"

Hi!
You are really needing to 'group' the <paragraph> elements by when the
<style> value changes. In which case something like...

Well your xsl's work with the data i published, but when i try to
rewrite it to use it with my data, it does not work because i do not
know the xsl:key statement enough to get it running - or better : i do
not know how to write the use - parameter to get it working ...


== XSL1 ================================================ *snipped*
== end of XSL1 =========================================
Here i get this output:
======================================================
<parsed>listing #1 text<text>listing #1 text</text>
<text>some text between 2 listings</text>listing #2
text</parsed>
======================================================

Is this correct??
However, if you are using MSXML 3.0 or MSXML 4.0 (pre SP2) then that
stylesheet will not work correctly due to a bug with current() in keys. An
alternative would be...

I have to work with MSXML :(
== XSL2 ================================================ *snipped*
== end of XSL2 =========================================

Here i get a different looking output:
======================================================
<parsed>listing #1 text<text>some text between 2
Hope this helps

I think it shows me that i have to use the xsl:key and key() functions
to get a matching solution with the existing schema.



Thanks Martin
 
M

Marrow

Hi Martin,
Is this correct??

How would I know?? :)
Well your xsl's work with the data i published, but when i try to
rewrite it to use it with my data, it does not work because i do not
know the xsl:key statement enough to get it running - or better : i do
not know how to write the use - parameter to get it working ...
...

Please, if the stylesheets don't work with your actual XML then surely the
logical thing to do would be to show that actual XML? ;)
I think it shows me that i have to use the xsl:key and key() functions
to get a matching solution with the existing schema.

No, not really, keys have nothing to do with schemas. XSLT 1.0 knows
nothing of schemas at all (input or output) - if you want the output to
validate against a given schema then that is down to the design of the
stylesheet to produce the right output... whatever that might be.

Cheers
Marrow
 
B

Buchleitner Martin

On Mon, 7 Jul 2003 13:27:51 +0100, "Marrow"

Hi!
Please, if the stylesheets don't work with your actual XML then surely the
logical thing to do would be to show that actual XML? ;)
Ok i could do this ;)

Here a part of my actual XML:
( This inherits everything which should be matched ... )


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<w:wordDocument
xmlns:w="http://schemas.microsoft.com/office/word/2003/2/wordml"
xmlns:wx="http://schemas.microsoft.com/office/word/2003/2/auxHint"
xml:space="preserve">
<w:body>
<wx:sect>
<w:p>
<w:pPr>
<w:pStyle w:val="MetaInfo"/>
</w:pPr>
<w:r>
<w:t>Documentnumber</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="Documentnumber"/>
</w:pPr>
<w:r>
<w:t>123456790</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="MetaInfo"/>
</w:pPr>
<w:r>
<w:t>Date</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="Date"/>
</w:pPr>
<w:r>
<w:t>20030708</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="MetaInfo"/>
</w:pPr>
<w:r>
<w:t>Title</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="Title"/>
</w:pPr>
<w:r>
<w:t/>
</w:r>
<w:r>
<w:br/>
<w:t>over 2 lines ....</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ArticelNumber"/>
</w:pPr>
<w:r>
<w:t>Articel I</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ArticelDescription"/>
</w:pPr>
<w:r>
<w:t>A description which is reformated over</w:t>
</w:r>
<w:r>
<w:br/>
<w:t>2 lines with a nice break ;)</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ChapterNumber"/>
</w:pPr>
<w:r>
<w:t>1. Section</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ChapterDescription"/>
</w:pPr>
<w:r>
<w:t>Some Chapter description .....</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ChapterArea"/>
</w:pPr>
<w:r>
<w:t>And an area is also there ....</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ParagraphDescription"/>
</w:pPr>
<w:r>
<w:t>Example header.</w:t>
</w:r>
</w:p>
<wx:pBdrGroup>
<wx:borders>
<wx:top wx:val="solid" wx:bdrwidth="2" wx:space="1"
wx:color="000000"/>
<wx:left wx:val="solid" wx:bdrwidth="2" wx:space="1"
wx:color="000000"/>
<wx:bottom wx:val="solid" wx:bdrwidth="2" wx:space="1"
wx:color="000000"/>
<wx:right wx:val="solid" wx:bdrwidth="2" wx:space="1"
wx:color="000000"/>
</wx:borders>
<w:p>
<w:pPr>
<w:pStyle w:val="ParagraphText"/>
</w:pPr>
<w:r>
<w:t>Here is some text of this paragraph</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="listing"/>
<w:listPr>
<wx:t wx:val=" 1."/>
<wx:font wx:val="Times New Roman"/>
</w:listPr>
</w:pPr>
<w:r>
<w:t>This is the first listing entry</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="listing"/>
<w:listPr>
<wx:t wx:val=" 2."/>
<wx:font wx:val="Times New Roman"/>
</w:listPr>
</w:pPr>
<w:r>
<w:t>And here comes an hand-made listing....</w:t>
</w:r>
<w:r>
<w:br/>
<w:t>
a) but it only has to be written in seperate lines ...
</w:t>
</w:r>
<w:r>
<w:br/>
<w:t>
b) and a HTML br- Tag can be used for this .....
</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ParagraphText"/>
</w:pPr>
<w:r>
<w:t>Here is some text at the end of this paragraph</w:t>
</w:r>
</w:p>
</wx:pBdrGroup>
<w:p>
<w:pPr>
<w:pStyle w:val="FooterText"/>
</w:pPr>
<w:r>
<w:t>Here is some footer in ....</w:t>
</w:r>
</w:p>
</wx:sect>
</w:body>
</w:wordDocument>


And this document should be linked to this output by the stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<document>
<head>
<metainfo type="DocumentNumber">123456790</metainfo>
<metainfo type="Date">20030708</metainfo>
<metainfo type="Title">This title goes<br/>over 2 lines
.....</metainfo>
</head>
<body>
<article>
<number>Article I</number>
<description>A description which is reformated over<br/>
2 lines with a nice break ;)</description>
<section>
<number>1. Section</number>
<description>Some Chapter description</description>
<paragraph>
<description>Example header</description>
<break>
Here is some text of this paragraph
</break>
<list>
<item>This is the first listing entry</item>
<item>And here comes an hand-made listing....<br/>
a) but it only has to be written in seperate lines ..<br/>
b) and a HTML br- Tag can be used for this .....
</item>
</list>
<break>
Here is some text at the andof this paragraph
</break>
</paragraph>
</section>
</article>
</body>
<footer>
<metainfo type="footer">Here is some footer in ....</metainfo>
</footer>
</document>


The <body> could inherit tags of <article> or <paragraph>.


Martin
 
A

augruy

On Mon, 7 Jul 2003 11:49:24 +0100, "Marrow"

Hi out there!
== XSL1 ================================================
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="xml" indent="yes"/>
<xsl:key name="kNonEqFollow" match="paragraph"
use="generate-id(following-sibling::paragraph[style != current()/style])"/>
<xsl:template match="document">
<parsed>
<xsl:apply-templates select="paragraph[not(preceding-sibling::paragraph)
or style != preceding-sibling::paragraph[1]/style]"/>
</parsed>
</xsl:template>

<xsl:template match="paragraph[style = 'listing']">
<!-- find the first following with a different <style> -->
<xsl:variable name="non-eq"
select="generate-id(following-sibling::paragraph[style !=
current()/style])"/>
<list>
<xsl:for-each select=". | key('kNonEqFollow',$non-eq)">
<item>
<xsl:value-of select="text"/>
</item>
</xsl:for-each>
</list>
</xsl:template>

<xsl:template match="paragraph[style = 'text']">
<!-- find the first following with a different <style> -->
<xsl:variable name="non-eq"
select="generate-id(following-sibling::paragraph[style !=
current()/style])"/>
<xsl:copy-of select="(. | key('kNonEqFollow',$non-eq))/text"/>
</xsl:template>

</xsl:stylesheet>
== end of XSL1 =========================================

However, if you are using MSXML 3.0 or MSXML 4.0 (pre SP2) then that
stylesheet will not work correctly due to a bug with current() in keys. An
alternative would be...

I am using Xalan-j so it should be ok or?

I adapted now this XSL1 to my needings:
=========XSL=============================================
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:key name="noneq" match="paragraph"
use="generate-id(following-sibling::paragraph[inner[style !=
current()/inner/style]])"/>
<xsl:template match="document">
<parsed>
<xsl:apply-templates select="bording"/>
</parsed>
</xsl:template>
<xsl:template match="bording">
<group>
<xsl:variable name="selection"
select="paragraph[not(preceding-sibling::paragraph)
or inner/style != preceding-sibling::paragraph[1]/inner/style]"/>
<xsl:apply-templates select="$selection"/>
</group>
</xsl:template>
<!-- -->
<xsl:template match="paragraph[inner[style='Listing']]">
<xsl:variable name="non-eq"
select="generate-id(following-sibling::paragraph[inner[style !=
current()/inner/style]])"/>
<xsl:variable name="nodes" select="key('noneq',$non-eq)"/>
<list>
<xsl:for-each select=". | $nodes">
<item>
<xsl:value-of select="rich/text"/>
</item>
</xsl:for-each>
</list>
</xsl:template>
<!-- -->
<xsl:template match="paragraph[inner[style='ParagraphText']]">
<xsl:variable name="non-eq"
select="generate-id(following-sibling::paragraph/inner[style !=
current()/inner/style])"/>
<xsl:for-each select="(. | key('noneq',$non-eq))">
<absatz>
<xsl:value-of select="rich/text"/>
</absatz>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
=========end of XSL=======================================

the corresponding XML is
=========XML=============================================
<?xml version="1.0" encoding="ISO-8859-1"?>
<document>
<bording>
<paragraph>
<inner>
<style>ParagraphText</style>
</inner>
<rich>
<text>a text within a paragraph</text>
</rich>
</paragraph>
<paragraph>
<inner>
<style>Listing</style>
</inner>
<rich>
<text>listing item #1</text>
</rich>
</paragraph>
<paragraph>
<inner>
<style>Listing</style>
</inner>
<rich>
<text>listing item #2</text>
</rich>
</paragraph>
<paragraph>
<inner>
<style>ParagraphText</style>
</inner>
<rich>
<text>a text at the end of a paragraph</text>
</rich>
</paragraph>
</bording>
<bording>
<paragraph>
<inner>
<style>ParagraphText</style>
</inner>
<rich>
<text>2 a text within a paragraph</text>
</rich>
</paragraph>
<paragraph>
<inner>
<style>Listing</style>
</inner>
<rich>
<text>2 listing item #1</text>
</rich>
</paragraph>
<paragraph>
<inner>
<style>Listing</style>
</inner>
<rich>
<text>2 listing item #2</text>
</rich>
</paragraph>
</bording>
</document>
=========end of XML=======================================

these two produce following output:

=========Output=============================================
<?xml version="1.0" encoding="UTF-8"?>
<parsed>
<group>
<absatz>a text within a paragraph</absatz>
<list>
<item>listing item #1</item>
<item>listing item #2</item>
</list>
<absatz>a text at the end of a paragraph</absatz>
<absatz>2 listing item #1</absatz>
<absatz>2 listing item #2</absatz>
</group>
<group>
<absatz>2 a text within a paragraph</absatz>
<list>
<item>a text at the end of a paragraph</item>
<item>2 listing item #1</item>
<item>2 listing item #2</item>
</list>
</group>
</parsed>
=========end of Output=======================================

But i want an output like the following:
==========================================================
<?xml version="1.0" encoding="UTF-8"?>
<parsed>
<group>
<absatz>a text within a paragraph</absatz>
<list>
<item>listing item #1</item>
<item>listing item #2</item>
</list>
<absatz>a text at the end of a paragraph</absatz>
</group>
<group>
<absatz>2 a text within a paragraph</absatz>
<list>
<item>2 listing item #1</item>
<item>2 listing item #2</item>
</list>
</group>
</parsed>
==========================================================


How can i rewrite my matching key to work only with the paragraph tags
within the bording - element??


TIA, Martin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top