XSL — Need to do something when text() is just 

2019-08-02 17:45发布

Want to do some parsing/modification of the text contents of a node if all that text() returns is a pure text string. No XML inside.

For example

<test>some <super>1</super> text here</test>

text() for <test> returns just "some ". This is a case where I do not want to output the text and instead want to call apply-templates.

Is there anyway to tell or is this situation too ambiguous for XSL to handle?

Edit: The output I want is exactly this

Reasoning is this: Sometimes there is just text that has a word split by a "/". I want to add spaces before and after so it's " / " instead. But sometimes the same node has xML in it.

some <super>1</super> text here

标签: xml xslt text
4条回答
趁早两清
2楼-- · 2019-08-02 18:26

The test or predicate count(text()) = count(node()) should work to make the distinction.

查看更多
Melony?
3楼-- · 2019-08-02 18:27

Actually in the situation described, text() returns a sequence of two text nodes, "some " and " text here", but in XSLT 1.0, many operations on a sequence (or set) of nodes ignore all nodes except the first.

You haven't said what output you want. But the usual way of processing mixed content is to call apply-templates to process all the children. Explicit use of text() is very rarely the right thing to do.

查看更多
爷的心禁止访问
4楼-- · 2019-08-02 18:44

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vLetters"
    >qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM</xsl:variable>
    <xsl:variable name="vDots"
    >....................................................</xsl:variable>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="test/text()" name="tokenize">
        <xsl:param name="pString" select="string()"/>
        <xsl:variable name="vString"
         select="translate($pString,$vLetters,$vDots)"/>
        <xsl:choose>
            <xsl:when test="contains($vString,'./.')">
                <xsl:variable name="vOffset"
                 select="string-length(substring-before($vString,'./.'))"/>
                <xsl:value-of select="substring($pString,1,$vOffset+1)"/>
                <xsl:text> / </xsl:text>
                <xsl:call-template name="tokenize">
                    <xsl:with-param name="pString"
                     select="substring($pString,$vOffset+3)"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

With this input:

<test>This is an answer/solution to <user>OP/bobber205</user>'s question/problem</test>

Output:

<test>This is an answer / solution to <user>OP/bobber205</user>'s question / problem</test>

Note: One way (another would be with modes) for also splitting descendant is to use test//text() as pattern.

查看更多
祖国的老花朵
5楼-- · 2019-08-02 18:50

You can test to see if the current node has children:

<xsl:template match="/test">
  <xsl:choose>
    <xsl:when test="./*">
      <xsl:text>children: </xsl:text>
      <xsl:apply-templates />
    </xsl:when>
    <xsl:otherwise>
        <xsl:text>just text: </xsl:text>
        <xsl:value-of select="./text()" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
查看更多
登录 后发表回答