views:

168

answers:

2

Hi,

I am having a problem while doing some XSLT pre-processing in my java program. We get an asterisk (*) from a mainframe program when it wants to blank out a value, which my java process has to treat like a blank or empty tag. So we apply an xslt to the input before my jaxb process.

We are applying this xslt :

  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:output method="xml" indent="no"/>
  <xsl:template match="@*[. = '*']">
    <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
      <xsl:text></xsl:text>
    </xsl:attribute>
  </xsl:template>
  <xsl:template match="*[. = '*']">
    <xsl:copy>
      <xsl:text></xsl:text>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

The above xslt works fine for ALMOST all test cases. Except in the case where there is only ONE sub-element and that happens to be an asterisk.

For instance consider this in the input:

<MYROOT><Address3><Line2>*</Line2><Line3>*</Line3></Address3></MYROOT>

works well. It produces this output:

<MYROOT><Address3><Line2/><Line3/></Address3></MYROOT>

The xml input below, however , produces an incorrect response.

<MYROOT><Address4><PermanentAddress><Line2>*</Line2></PermanentAddress></Address4></MYROOT>

But instead of giving the response as

<MYROOT><Address4><PermanentAddress><Line2></Line2></PermanentAddress></Address4></MYROOT>

It gives this:

<MYROOT/>

Please help. Any help is appreciated as I did not have this test case while testing my code.

A: 

That's because . is the inner text, which is a concatenation of all inner text nodes. You need to make sure in your condition that there is no child node either or only a text node with * as contents.

This should work:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml" indent="no"/>

    <xsl:strip-space elements="*"/>

    <xsl:template match="*[not(*) and (. = '*')] | @*[. = '*']">
        <xsl:copy />
    </xsl:template>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
Lucero
Sorry, it was not exactly yelling -- just needed to be easily noticed.
Dimitre Novatchev
A: 

Replace:

<xsl:template match="*[. = '*']"> 
    <xsl:copy> 
      <xsl:text></xsl:text> 
    </xsl:copy> 
  </xsl:template>

with

  <xsl:template match="*[not(*) and not(text()[2])]/text()[.='*']"/>

This is much more efficient than having to calculate the string value of every element, because the string value of an element is the concatenation of all its descendent text nodes.

Dimitre Novatchev
@Dimitre, your code will delete all text nodes which are a single star. this may be too much, such as in `<a>*<b/>*</a>`.
Lucero
@Lucero: Good observation, thanks. I have modified the solution accordingly.
Dimitre Novatchev
@Dimitre, still not good as far as I understand the question the following should not be trimmed: `<a>*<b/></a>` because it is not a "tag" [sic] with exactly one `*` in it.
Lucero
Thank you both for your reply.My requirement is that if a tag has only a single "*", we have to replace them with empty tags.We do NOT expect to see "*" as a part of any input data.
SGB
@SGB: Yes, then my solution produces the results you need. Also, the specifics of your data do not remove the inefficiencies in using `". = '*'"`. THe XSLT processor will need to make the concatenation of all text-node descendents of any element, in order to decide which of the templates match most.
Dimitre Novatchev
@Lucero: Yes, it is a valid remark -- I edited my answer.
Dimitre Novatchev
Thank you Demitre and Lucero.<P>I ended up using Lucero's solution as it was closest to what I currently have and I do not quite understand Dimitre's solution. And we have to deploy shortly. <P>I tested Lucero's xslt with many test cases, and it worked on all occasions. If there is a test case where it is broken, please let us know.. <P>Thanks again to both of you. All the help is truly appreciated.<P>
SGB
@SGB: You must be joking: "Thanks again to both of you. All the help is truly appreciated". If you really appreciated any answer, why didn't you accept it? The real name of this is *ungratefulness*. From now on, when I see a question of yours, I'll know to avoid it!
Dimitre Novatchev
@Dimitre, only one answer may be accepted. It's unfair to blame SGB for accepting another answer which he felt was what he needed, and since the rep of SGB is still low he couldn't upvote you. Take it easy.
Lucero
@SGB, thanks for the feedback and for accepting the answer. Please be reassured that you did nothing wrong.
Lucero
@Lucero: You are mixing cause and effect. When I wrote that comment he was just saying "thank you both" and he *hadn't* accepted any answer. This is explicitly written in my comment. I haven't seen such case on SO for almost two years. I am glad that finally he accepted your answer, so this means my comment really was useful.
Dimitre Novatchev
@ Dimitre, I appreciate you taking the time to help out.I took both your answers and reviewed it with a co-worker who gave the original xslt. We tested Lucero's solution first as it was closest to the current version and it passed all the test cases we had. As we have to deploy in short order (tomorrow) we had to make the change and deploy it last night itself, so did not have the time to test your solution. But I do appreciate you taking the time to help out.Hope that clarifies the situation.A final Sincere Thank you to both.Cheers,SGB
SGB
@SGB, You grossly misunderstand my comments. I did not at any moment demand that my answer should be accepted. I demanded that instead of just saying "Thanks again to both of you" and not accepting *any* answer you should accept *one of the answers*. I see that my comments achieved their goal -- now you have accepted an answer. In the future don't forget that the main recognition at SO is upvoting and accepting an answer. Saying "thank you both" without accepting any answer is a very bad joke.
Dimitre Novatchev
@Dimitre, thanks for the clarification. Since the answer was accepted when I returned here I didn't see the "unaccepted" state at all, which made me understand your comment as requiring to get the accepted answer. I'm sorry for the misunderstanding.
Lucero
@Lucero: NP. Time-zone difference is not an absolute obstacle to reach understanding :). BTW, Is my browser faulty or do I see correctly that your answer *isn't* accepted -- again at this time???
Dimitre Novatchev
@Dimitre, thanks for your understanding. And you're right, it seems to be no longer accepted. Very strange.
Lucero