开发者

xsl - tag position with text mixed in parent

In XSL 1.0, I am trying to distinguish between the following 2 scenarios which both occur within the input XML I need to process and each to be handled differently.

Scenario 1

<tag1><tag2/> some text</tag1>

Scenario 2

<tag1>some text <tag2/></tag1>

I have a template which matches at the <tag2/> level, within this I want scenario 1 to ignore <tag2/>, in scenario 2 I want to insert a <br/> in place of <tag2/>.

I have searched on here and on google but can't seem to figure out how to distinguish based on the position of <tag2/> within <tag1>.

I have looked into preceding-sibling and generate-id and tried to use something like:-

 not(
    generate-id(
       preceding-sibling::nod开发者_运维技巧e()[1]
    )
  = generate-id(
       preceding-sibling::text()[1]
    )
 )

and the

position()

of <tag2/> doesn't seem to help here either as both appear to be operating at the node level??

Any ideas would be welcomed?

Thanks Roger


Look at these patterns:

node()[1]

This match first node child.

node()[1][self::tag2]

This match first node child which is also a tag2 element.

node()[not(self::text()[not(normalize-space())])][1][self::tag2]

This match first node child which is not a whitespace only text node and also a tag2 element (in case you preserve whitespace only text node as you should with XHTML input).

I give you this approach because the first and second patterns are streamable (preceding axis is not streamable).

Note: The second must be rewrite as node()[position() = 1 and self::tag2].


The following stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="tag2[preceding-sibling::text()]">
        <br/>
    </xsl:template>
</xsl:stylesheet>

On this input:

<items>
    <tag1><tag2/>some text</tag1>
    <tag1>some text <tag2/></tag1>
</items>

Produces:

some text
some text <br/>

A more complex solution would require additional information about the desired output.


A simpler and more fundamental solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "node()[self::tag2 and position()=1]"/>
 <xsl:template match=
  "node()[self::tag2 and position()=2]">
  <br/>
 </xsl:template>
</xsl:stylesheet>

When applied on this XML document:

<tag1><tag2/> some text</tag1>

produces the wanted, correct result:

<tag1> some text</tag1>

When applied on this document:

<tag1>some text <tag2/></tag1>

again the wanted, correct answer is produced:

<tag1>some text <br/>
</tag1>

Explanation:

  1. The identity rule (template) copies every node as-is.

  2. The first template that is overriding the identity rule matches any node whose name is tag2 and whose position in the node-list is 1. It has no body so the tag2 element is ignored.

  3. The second template that overrides the identity rule is similar to the first, but the position of the matched tag2 node has to be 2. In this case it is replaced by <br/>.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜