简体   繁体   中英

Need help manipulating text in a <p> tag without losing children nodes when transforming xml data to html

I have an xml document that is being transformed with XSLT 2.0 to an HTML document for publication.

The issue I have is that there are soft line breaks (LF) that exist in the P tags that need to be preserved in the HTML as BR tags, but when I replace the LF characters for BR tags I lose any XREF tags within the text.

Sample .xml

<p>Section 1 
<xref href="https://www.google.com/section1">Link</xref>
Section 2
<xref href="https://www.google.com/section2">Link</xref>
Section 3
<xref href="https://www.google.com/section3">Link</xref>
</p>

This should look something like this in the output

<p>Section 1 </br><xref href="https://www.google.com/section1">Link</xref><br/>Section 2 </br><xref href="https://www.google.com/section2">Link</xref><br/>Section 3 </br><xref href="https://www.google.com/section3">Link</xref><br/></p>

NOTE: I haven't formatted the above to illustrate the hardcoded LFs that get converted into BR tags.

We tried the following solution, but the selected string already ignores the child node:

<xsl:stylesheet 
    version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output encoding="UTF-8"/>
    <xsl:template name="replace">
        <xsl:param name="string"/>
        <xsl:choose>
            <xsl:when test="contains($string,'&#10;') ">
                <xsl:value-of select="substring-before($string,'&#10;')"/>
                <br/>
                <xsl:call-template name="replace">
                    <xsl:with-param name="string" select="substring-after($string,'&#10;')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:if test="xref">
                    <xsl:copy-of select="xref"/>
                </xsl:if>
                <xsl:value-of select="$string"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="p">
        <p>
            <xsl:call-template name="replace">
                <xsl:with-param name="string" select="."/>
            </xsl:call-template>
        </p>
    </xsl:template>
</xsl:stylesheet>

So simply I need help to replace LFs with BR tags without affecting child XREF nodes.

As you say you use XSLT 2 it seems using xsl:analyze-string would make the job of finding and replacing characters by certain elements easier.

As for the problem with your current approach, just write an <xsl:template match="p/text()"> or <xsl:template match="p//text()"> (if you want to do the replacement in descendants, too) and do any replacement directly in the text nodes, for the rest you use the identity transformation. That way you preserve the document structure and don't strip any child elements of the p elements.

  <xsl:template match="p/text()">
      <xsl:analyze-string select="." regex="&#10;">
          <xsl:matching-substring>
              <br/>
          </xsl:matching-substring>
          <xsl:non-matching-substring>
              <xsl:value-of select="."/>
          </xsl:non-matching-substring>
      </xsl:analyze-string>
  </xsl:template>

https://xsltfiddle.liberty-development.net/6r5Gh4d

If you don't have an XSLT 3 processor like Saxon 9.8 or later at your disposal spell out the identity transformation as

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

and drop the xsl:mode declaration used in the XSLT Fiddle example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM