tags:

views:

424

answers:

5
+1  Q: 

xml xslt question

Hi folks,

I have an xml that has text within "word" elements e.g

<word>Police</word>
<word>confirmed</word>
<word>they are</word>
<word>questioning</word>
<word>a</word>
<word>man</word>

The problem is when I apply the xslt the text appears like "Policeconfirmedthey arequestioningaman".

Here is the xslt snippet that does this transform

<Paragraph>
 <xsl:for-each select="./speaker/segment">
 <xsl:value-of select="./nbest"/>
 </xsl:for-each>
</Paragraph>

Can anyone offer any help as to how I can display this as "Police confirmed they are questioning a man"?

Many thanks.

A: 
rravuri
not that I downvoted you, but you would have to define the   entity
annakata
Just define the   character at the beginning of your xslt should solve the issue:<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
gizmo
+4  A: 

You can conditionally add a space between words based on word's position. The following snippet shows how to add a whitespace after all but last word.

<xsl:template match="//words">
    <xsl:for-each select="word">
      <xsl:value-of select="."/>
      <!-- Check word's position -->
      <xsl:if test="position()!=last()">
      <!-- Add a whitespace if it's not the last word -->
        <xsl:text> </xsl:text>
      </xsl:if>
    </xsl:for-each>
</xsl:template>

If you produce HTML output, you can use info from this post to find out how to add a whitespace (instead of < xst:text > in my code snippet)

aku
You probably know this already, but for completeness sake I would suggest that the use of '//' should be discouraged for performance reasons. if you know the full path for the nodes you're interested in let the engine know, otherwise it will have to scan the entire document for possible matches
Yossi Dahan
it's a quick code snippet created to show solution to a specific problem and not a coding guideline
aku
+3  A: 

Add a space character.

Simple way:

<Paragraph>
 <xsl:for-each select="./speaker/segment">
   <xsl:value-of select="./nbest"/>&#160;
 </xsl:for-each>
</Paragraph>

Slightly more complex way to effectively trim the string:

<Paragraph>
 <xsl:for-each select="./speaker/segment">
   <xsl:if test="not(position() = 1)">&#160;</xsl:if>
   <xsl:value-of select="./nbest"/>
 </xsl:for-each>
</Paragraph>

And some xpath ways: normalize-space, substring-before, substring-after in various forms.

annakata
This will add a non-breaking space, which will mean that the output cannot be wrapped, will be a normal space.
davidsheldon
fair point: choose your spaces as appropriate people
annakata
+2  A: 

it is almost like "aku" answer. But "aku" answer creats one paragraph.

 <xsl:for-each select="./speaker/segment">  
 <Paragraph>   
    <xsl:for-each select="./nbest/word"/>        
      <xsl:value-of select="."/>
        <xsl:if test="position()!=last()">
          <xsl:text> </xsl:text>
        </xsl:if>        
    </xsl:for-each>
 </Paragraph>
</xsl:for-each>
Schwartser
+2  A: 

The reason they are running together is because the stylesheet is using a built-in template to match against which is collapsing the white space. I don't see where you are explicitly calling the <word/> or surrounding XML, so I'm assuming it's an <xsl:apply-templates /> call somewhere. You should just need to just define a match template as such:

<xsl:template match="word">
    <xsl:value-of select="." />&#160;
</xsl:template>

Whitespace is significant, so if in the above solution, you find it messing things up, you can wrap the   within an <xsl:text/> node, and whitespace be gone.

Then when the word node is matched you get it spaced. Note: there will be an extra space at the end. To get rid of that it will be slightly longer.

<xsl:temmplate match="word">
    <xsl:value-of select="." />
    <xsl:if test=". !=../word[last()]">
        <xsl:text>&#160;</xsl:text>
    </xsl:if>
</xsl:template>

This will only work when applying-templates, and not when using value-of or copy-of xsl directives.

null
the reason is nothing to do with "built-in" (whatever you mean by that) vs apply-templates, it's purely that XSLT doesn't respect whitespace over different lines. Inserting a space character via hash code or xsl:text is the solution. Also, your position test is going to be relatively slow fwiw
annakata
Here is some information about the built-in template rules. http://www.w3.org/TR/xslt#built-in-rule
null