开发者

group content between 2 given element names

开发者 https://www.devze.com 2023-04-04 22:46 出处:网络
I\'m struggling a bit on converting a Filemaker XML file to something more userfriendly. FM by default stores every single sentence of a paragraph in an element, and I\'d like all these sentences grou

I'm struggling a bit on converting a Filemaker XML file to something more userfriendly. FM by default stores every single sentence of a paragraph in an element, and I'd like all these sentences grouped.

Below XML shows how this looks like in it's raw form :

<Para>
<ParaLine>
    <String>This is just some spacefiller, so some text to </String>
</ParaLine>
<ParaLine>
    <String>show how things look now. Go to </String>
    <XRef>
        <XRefName value="Heading"/>
    </XRef>
    <String>“</String>
    <String>More info here</String>
    <String>” </String>
</ParaLine>
<ParaLine>
    <String>(page</String>
    <Char value="HardSpace" type="enum"/>
    <String>27)</String>
    <XRefEnd/>
    <String>to get more details.</String>
</ParaLine>
</Para>

My aim is twofold, first I'd like to get all string values in any [para] grouped. That's relatively easy to achieve with following xlst :

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" xmlns="http://www.w3.org/1999/xhtml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="text()">
    <xsl:value-of select="normalize-space(.)"/>
</xsl:template>

<xsl:template match="/">
    <xsl:result-document href="test.xml">
        <xsl:apply-templates/>
    </xsl:result-document>
</xsl:template>

<xsl:template match="String">
    <xsl:choose>
        <xsl:when test="preceding-sibling::*[1][name()='String']">
            <xsl:text> </xsl:text>
            <xsl:value-of select="text()"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="text()"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="ParaLine">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="Char[@value='HardSpace']">
    <xsl:text&开发者_StackOverflow中文版gt; </xsl:text>
</xsl:template>

</xsl:stylesheet>

So my current output looks like this :

<Para>This is just some spacefiller, so some text to show how things look now. Go to
 <XRef><XRefName value="Heading"/></XRef>
 “ More info here ” (page 27)
 <XRefEnd/>to get more details.
 </Para>

However, my second objective is to get the content between [XRef] and [XRefEnd] in a single tag, I can do this using a couple off additional transformations, but I was wondering if it would be possible in a single trip. My ultimate 'dream' would be to become below XML output in one single trip :

<Para>
<local xml:lang="en">This is just some spacefiller, so some text to show how things look now. Go to 
<XRef XRefName="Heading">“ More info here ” (page 27)</XRef>
to get more details.</local>

Any tips on how I can do this with limited amount of transformations ?

Thanks in advance !


Here is an example:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

  <xsl:output indent="yes"/>

  <xsl:template match="Para">
    <xsl:copy>
      <xsl:for-each-group select="ParaLine/*" group-starting-with="XRef">
        <xsl:choose>
          <xsl:when test="self::XRef">
            <xsl:variable name="name" select="XRefName/@value"/>
            <xsl:for-each-group select="current-group() except ." group-ending-with="XRefEnd">
              <xsl:choose>
                <xsl:when test="position() eq 1">
                   <XRef XRefName="{$name}">
                     <xsl:apply-templates select="current-group()[position() ne last()]"/>
                   </XRef>
                 </xsl:when>
                 <xsl:otherwise>
                   <xsl:apply-templates select="current-group()"/>
                 </xsl:otherwise>
               </xsl:choose>
            </xsl:for-each-group>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="current-group()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

When I use Saxon 9.3 with above stylesheet on your posted input I get the following result:

<?xml version="1.0" encoding="UTF-8"?>
<Para>This is just some spacefiller, so some text to show how things look now. Go to <XRef XRefName="Heading">“More info here” (page27)</XRef>to get more details.</Para>
0

精彩评论

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

关注公众号