如何展开和包围两个其他元素之间的元素

问题描述 投票:0回答:1

我目前正在将 MS Access 查询传输到 XML,然后使用 XSLT 3.0 将 XML 输入到 FrameMaker 中以进行发布。在此过程中,我必须使用 David Carlisle 的 HTML 解析器(https://github.com/davidcarlisle/web-xslt/tree/main?tab=readme-ov-file)解析各种 Access RTF 字段来转换信息我已将不同的字段放入 XML 中的节点中。

我正在尝试实现第二级或第三级项目符号,RTF 本身不支持该功能(至少在 Access 中实现)。为此,我在字段中创建文本,然后将其解析为 XML 元素以指示二级项目符号。我遇到的一个问题是 Access 的 RTF 字段正在任何文本元素周围应用

<div>
<font>
节点,因此当我尝试执行此操作时(请注意,
<list2>
“节点”只是驻留在节点内的文本然后应用 HTMLParse):

- item 1
<list2>
- subitem 1
</list2>

它变成了更接近这个的东西:

- item 1
<div><font><list2></font></div>
- subitem 1
<div><font></list2></font></div>

这当然行不通,因为这不是格式良好的 XML。有没有办法使用 XSLT 将其转换为子项包含在列表节点中的初始块?一种选择是从

开始
- item 1
<div><font><list2></list2></font></div>
- subitem 1
<div><font><list2></list2></font></div>

如果有帮助,但我不知道如何从这里到达那里。可能还有一些额外的问题,因为我不太了解节点遍历,但这些列表节点不是输入 XML 中的节点,而是通过 HTMLParse 创建的。

编辑:我试图简化示例中的事情,但我遗漏了重要的细节。我尝试共享 XSLT Fiddle 链接,但它不起作用。以下是 XML 文件,后跟 XSLT。请注意,我相当有信心 XSLT 文件没有完美配置,因为我是在毫无知识的情况下开始构建它的,并且随着时间的推移添加了一些东西。如果您有关于消除冗余的建议或我应该使用的最佳实践,我也将不胜感激。

XML 输入:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2024-03-05T13:21:03">
<TEQuery>
<PubNum>1.311</PubNum>
<TAXSORT>1</TAXSORT>
<IntID>PC109S</IntID>
<TEName>Oi</TEName>
<ORS>311</ORS>
<Carryforward>No</Carryforward>
<Sunset>None</Sunset>
<Refundable>No</Refundable>
<Enacted>2001</Enacted>
<Transferable>No</Transferable>
<LastRevPIT>Not</LastRevPIT>
<CurRevPIT>Not</CurRevPIT>
<LastRevCorp>Not</LastRevCorp>
<CurRevCorp>Not</CurRevCorp>
<LastRevTotal>Not</LastRevTotal>
<CurRevTotal>Not</CurRevTotal>
<RevEstFtNote>&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&lt;em&gt;* In certain cases, to conform with taxpayer privacy disclosure laws, revenue impact numbers are not provided for tax expenditures that may affect at most a few taxpayers. &lt;/em&gt;&lt;/font&gt;&lt;/div&gt;</RevEstFtNote>
<Description>
&lt;ul&gt;
 &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;The proposed facility is intended to operate for at least 10 years. &lt;/font&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;list2&amp;gt;&lt;/font&gt;&lt;/div&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;between July 1, 2011, and October 5, 2017, receive compensation (wages and benefits) at least 50 percent higher than the per capita personal income (PCPI) for the county at the time of the application, or at least equal to county PCPI while providing health insurance benefits, or,&lt;/font&gt;&lt;/li&gt;
 &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;since October 6, 2017 (HB 2066, 2017):&lt;/font&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;/list2&amp;gt;&lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;list3&amp;gt;&lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;(i) receive compensation meeting the above minimums or that is at least 30 percent more than county PCPI for locations outside any metropolitan statistical area, and&lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;(ii) (in all cases) receive an average annual wage at least equal to the then current average wage for the county. &lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;/list3&amp;gt;&lt;/font&gt;&lt;/div&gt;
</Description>
<Purpose>&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;The statutes that allow this expenditure do not explicitly state a purpose. Presumably, the purpose is to encourage business development in low-income areas with high unemployment rates, especially those areas with low population.&lt;/font&gt;&lt;/div&gt;</Purpose>
<WhoBenefits/>
<Evaluation>
&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;Other than its policy bias toward rural locations and against the expansion of existing business operations, this tax expenditure does not favor one group of industries in Oregon over another. Finally, like a tax credit, its effectiveness as an incentive depends on the taxpayer’s having an Oregon tax liability, but the 10‑year exemption period and potential for the new facility to generate additional taxable income could mitigate that issue.&lt;/font&gt;&lt;/div&gt;</Evaluation>
<TaxType>Personal &amp; Corporate Income Taxes</TaxType>
<Program>Economic/Community</Program>
<ExpType>Subtraction</ExpType>
<ProgramSort>3</ProgramSort>
<ExpTypeSort>4</ExpTypeSort>
<SectionName>Oregon Subtractions</SectionName>
<HeaderName>Section 1.3 - Oregon Subtractions</HeaderName>
<SectionLevel>Subsection</SectionLevel>
<SectionText></SectionText>
</TEQuery>
</dataroot>

XSLT

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:dc="data:,dpc"
  exclude-result-prefixes="#all">
  
<xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes" />
  
  
<xsl:import href="https://raw.githubusercontent.com/davidcarlisle/web-xslt/main/htmlparse/htmlparse.xsl"/>

<xsl:strip-space elements="* except TitleTab"/>
<!-- CHANGE THESE EACH YEAR-->
<xsl:variable name="lastbiennium" select = "'2023-25'"/>
<xsl:variable name="curbiennium" select = "'2025-27'"/>
<xsl:variable name="AVExemptYear" select = "'2021-22'"/>

  
  <xsl:mode on-no-match="shallow-copy"/>
  
  <!--THIS CREATED ISSUES, LEAVING COMMENTED OUT IN CASE IT IS NECESSARY added in late in the process, seems to help get rid of some of the whitespace issues I am coming across
 <xsl:template match="text()"> 
    <xsl:value-of select="normalize-space()"/>
</xsl:template>
  -->
<!-- This main piece here copies over all of the information from the original XML output by Access, and it reorganizes the data by Chapter, Section, Tax Type, and Expenditure Type. It adds in a variety of sort variables as well. -->
  <xsl:template match="dataroot">     
  <TER>
    <xsl:for-each-group select="TEQuery" group-by="TaxType">
      <Chapter>
        <xsl:attribute name="TaxSort" select="TAXSORT"/>
        <ChapterName>
        <xsl:attribute name="TaxSort" select="TAXSORT"/> <!-- duplicated so that I can easily print this along with the Name-->
        <xsl:value-of select="TaxType"/>
        </ChapterName>
        <xsl:if test = "current-group()/TAXSORT &gt;= 1">
            <TOCChapterHeader>
               <xsl:value-of  select="concat('Chapter ',TAXSORT,': ',TaxType)"/>
            </TOCChapterHeader>
        </xsl:if>
        <xsl:if test = "current-group()/TAXSORT &lt; 1">
            <TOCChapterNoHeader>
               <xsl:value-of  select="TaxType"/>
            </TOCChapterNoHeader>
        </xsl:if>
            <xsl:if test="ChapterText">
          <ChapterText>
             <xsl:apply-templates select="dc:htmlparse(ChapterText, '', true())"/>
          </ChapterText>
        </xsl:if>
        <xsl:for-each-group select="current-group()" group-by="SectionName">
          <Section>
            <xsl:attribute name = "SectionName" select = "SectionName"/>
            <xsl:attribute name = "SectionLevel" select = "SectionLevel"/>
            <xsl:attribute name = "HeaderName" select = "HeaderName"/>
            <xsl:apply-templates select = "Section"/> <!-- Next line is difficult. When do we want Section Name to print in the report?-->
            <xsl:if test="(current-group()/TAXSORT &lt; 1 and SectionLevel != 'Chapter Section' and SectionLevel != 'SubNoTOC') or (current-group()/TAXSORT >= 1 and (SectionLevel = 'Section' or SectionName = 'Other Federal Provisions (Unquantified or Disconnected)'))">
            <SectionName>
                <xsl:value-of select = "SectionName"/>
            </SectionName>
            </xsl:if>
            <xsl:choose>
                <xsl:when test = "SectionLevel = 'Section'">
                    <TOCSection>
                       <xsl:value-of  select="SectionName"/>
                    </TOCSection>
                </xsl:when>
                <xsl:when test = "current-group()/TAXSORT &lt; 1 and SectionLevel = 'Subsection'">
                    <TOCSubsectionIntro>
                       <xsl:value-of  select="SectionName"/>
                    </TOCSubsectionIntro>
                </xsl:when>
                <xsl:when test = "current-group()/TAXSORT &gt;= 1 and SectionLevel = 'Subsection'">
                    <TOCSubsectionTE>
                       <xsl:value-of  select="SectionName"/>
                    </TOCSubsectionTE>
                </xsl:when>
            </xsl:choose>
          <xsl:if test="SectionText">
          <SectionText>
             <xsl:apply-templates select="dc:htmlparse(SectionText, '', true())"/>
          </SectionText>
        </xsl:if>
          <xsl:for-each-group select="current-group()" group-by="ExpType">
            <ExpenditureType>
                <xsl:attribute name="ExpTypeSort" select="ExpTypeSort"/>
                <xsl:attribute name="ExpType" select="ExpType"/>
              <Program>
                <xsl:attribute name="ProgramSort" select="ProgramSort"/>
                <xsl:attribute name="Program" select="Program"/>
                <xsl:for-each-group select="current-group()" group-by="Program">
                  <xsl:for-each select="current-group()">
                    <TaxExpenditure>
                        <xsl:attribute name="id" select="IntID"/>
                        <xsl:attribute name="TaxSort" select="TAXSORT"/>
                        <xsl:attribute name="fedconnect" select="fedconnect"/>
                        <xsl:attribute name="PubNum" select="PubNum"/>
                        <xsl:attribute name="ExpName" select="TEName"/>
                        <xsl:attribute name="ExpType" select="ExpType"/>
                        <xsl:attribute name="SectionName" select="SectionName"/>
                        <xsl:attribute name="HeaderName" select="HeaderName"/>
                        <xsl:attribute name="SectionLevel" select="SectionLevel"/>
                            <PubNum>
                            <xsl:attribute name = "xml:space">preserve</xsl:attribute>
                            <xsl:value-of select="concat(PubNum,'    ')"/>
                            </PubNum>
                            <xsl:apply-templates select = "TEName"/>
                            <TEHead>
                              <xsl:choose>
                              <xsl:when test="TAXSORT = 1 and ExpType = 'Credit'">
                                <table>
                                  <tgroup>
                                    <xsl:attribute name="cols">2</xsl:attribute>
                                        <xsl:attribute name="pgwide">1</xsl:attribute>
                                        <colspec> <xsl:attribute name="colnum">1</xsl:attribute><xsl:attribute name="colwidth">.6*</xsl:attribute></colspec>
                                        <colspec> <xsl:attribute name="colnum">2</xsl:attribute><xsl:attribute name="colwidth">.4*</xsl:attribute></colspec>
                                      <tbody>
                                        <row>
                                          <entry><xsl:attribute name="align">left</xsl:attribute><paragraph><ORS><xsl:value-of select="ORS"/></ORS></paragraph></entry>
                                          <entry><xsl:attribute name="align">right</xsl:attribute><paragraph><Carryforward><xsl:value-of select="Carryforward"/></Carryforward></paragraph></entry>
                                        </row>
                                        <row>
                                          <entry><xsl:attribute name="align">left</xsl:attribute><paragraph><Sunset><xsl:value-of select="Sunset"/></Sunset></paragraph></entry>
                                          <entry><xsl:attribute name="align">right</xsl:attribute><paragraph><Refundable><xsl:value-of select="Refundable"/></Refundable></paragraph></entry>
                                        </row>
                                        <row>
                                          <entry><xsl:attribute name="align">left</xsl:attribute><paragraph><Enacted><xsl:value-of select="Enacted"/></Enacted></paragraph></entry>
                                          <entry><xsl:attribute name="align">right</xsl:attribute><paragraph><Transferable><xsl:value-of select="Transferable"/></Transferable></paragraph></entry>
                                        </row>
                                      </tbody>
                                  </tgroup>
                                </table>
                              </xsl:when>
                              <xsl:otherwise>
                                  <xsl:apply-templates select="IRC|ORS|Sunset|Enacted" />
                              </xsl:otherwise>
                              </xsl:choose>
                            </TEHead>
                      <xsl:apply-templates select="* except (IRC|ORS|Sunset|Enacted|Refundable|Carryforward|Transferable|PubNum|TAXSORT|TEName)" />
                    </TaxExpenditure>
                  </xsl:for-each>
                  </xsl:for-each-group>
              </Program>
            </ExpenditureType>
            </xsl:for-each-group>
            </Section>
          </xsl:for-each-group>
      </Chapter>
    </xsl:for-each-group>
    </TER>
  </xsl:template>

  <!-- This template does (optional recursively) what you need without the need of matching specific elements. This parses the RTF field that is similar to HTML, allowing us to manually create nodes withing other nodes. For example lists or graphics.-->
  <xsl:template match="text()[contains(.,'&lt;')]">
    <xsl:apply-templates select="dc:htmlparse(., '', true())"/>
  </xsl:template>
  
  
  <xsl:template match=
  "*[not(node())]
  |
   *[not(node()[2])
   and
     node()/self::text()
   and
     not(normalize-space())
     ]
  "/>
  
  <xsl:template match = "Section">
    <xsl:attribute name = "HeaderName" select = "HeaderName"/>
    <xsl:apply-templates select = "Section"/>
</xsl:template>



<xsl:template match="*"> <!--this is here to remove namespace prefixes that were propogating weirdly all over-->
    <!-- remove element prefix -->
    <xsl:element name="{local-name()}">
      <!-- process attributes -->
      <xsl:for-each select="@*">
        <!-- remove attribute prefix -->
        <xsl:attribute name="{local-name()}">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:for-each>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
  
  <!-- converts hyperlink formatting that we do in Access to something that Framemaker can handle. Creates text and type attributes that will be passed to FrameMaker as a hypertext marker. -->
 <xsl:template match="hypertext">
    <Hypertext>
      <xsl:choose>
        <xsl:when test="starts-with(./text(), 'https://')">
          <xsl:value-of select = "concat('message URL ',./text())" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select = "concat('message URL https://',./text())" />
        </xsl:otherwise>
      </xsl:choose>
    </Hypertext>
 </xsl:template>
 
 <!-- converts generic hyperlink formatting to something that Framemaker can handle. Creates text and type attributes that will be passed to FrameMaker as a hypertext marker. -->
 <xsl:template match="a">
    <hyperlink>
      <Hypertext>
      <xsl:choose>
        <xsl:when test="starts-with(@href, 'https://')">
          <xsl:value-of select = "concat('message URL ',@href)" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select = "concat('message URL https://',@href)" />
        </xsl:otherwise>
      </xsl:choose>
      </Hypertext>
      <xsl:apply-templates/>
    </hyperlink>
 </xsl:template>

 
 <xsl:template match="AVExempt">
    <AVExempt>
        <xsl:attribute name = "PrefixYear" select = '$AVExemptYear'/>
        <xsl:apply-templates/>
    </AVExempt>
 </xsl:template>
 
 
 
  <!-- reformats from simpler syntax analysts are asked to use to a format that can be passed to FrameMaker -->
  <xsl:template match="idref">
    <Xref>
      <xsl:attribute name="idref">
        <xsl:value-of select="text()"/>
      </xsl:attribute>
      <xsl:attribute name="type">shortTERef</xsl:attribute>
    </Xref>
  </xsl:template>
  <xsl:template match="fullexpref">
    <Xref>
      <xsl:attribute name="idref">
        <xsl:value-of select="text()"/>
      </xsl:attribute>
      <xsl:attribute name="type">TERef</xsl:attribute>
    </Xref>
  </xsl:template>

<!-- allows us to pass a link to a graphic to FrameMaker.-->
  <xsl:template match="graphic">
    <graphic>
      <xsl:attribute name="href">
        <xsl:value-of select="text()"/>
      </xsl:attribute>
    </graphic>
  </xsl:template>
  <!-- goal is to convert rev estimates to table format-->
  <!-- builds the rev estimate table for PIT/Corp -->
  <xsl:template match="LastRevPIT">
    <table>
      <tgroup>
        <xsl:attribute name="cols">4</xsl:attribute>
        <xsl:attribute name="pgwide">1</xsl:attribute>
        <colspec> <xsl:attribute name="colnum">1</xsl:attribute><xsl:attribute name="colwidth">.3*</xsl:attribute></colspec>
        <colspec> <xsl:attribute name="colnum">2</xsl:attribute><xsl:attribute name="colwidth">.233*</xsl:attribute></colspec>
        <colspec> <xsl:attribute name="colnum">3</xsl:attribute><xsl:attribute name="colwidth">.233*</xsl:attribute></colspec>
        <colspec> <xsl:attribute name="colnum">4</xsl:attribute><xsl:attribute name="colwidth">.233*</xsl:attribute></colspec>
        <thead>
          <row>
            <entry></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><white>Corporation</white></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><white>Personal</white></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><white>Total</white></paragraph></entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry><paragraph><xsl:value-of select="concat($lastbiennium,' Revenue Impact:')"/></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><LastRevCorp><xsl:value-of select="../LastRevCorp"/></LastRevCorp></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><LastRevPIT><xsl:value-of select="../LastRevPIT"/></LastRevPIT></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><LastRevTotal><xsl:value-of select="../LastRevTotal"/></LastRevTotal></paragraph></entry>
          </row>
          <row>
            <entry><paragraph><xsl:value-of select="concat($curbiennium,' Revenue Impact:')"/></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><CurRevCorp><xsl:value-of select="../CurRevCorp"/></CurRevCorp></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><CurRevPIT><xsl:value-of select="../CurRevPIT"/></CurRevPIT></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><CurRevTotal><xsl:value-of select="../CurRevTotal"/></CurRevTotal></paragraph></entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </xsl:template>
  
  <!-- builds the rev estimate table for Property Tax -->
  <xsl:template match="LastRevLoss">
    <table>
      <tgroup>
        <xsl:attribute name="cols">3</xsl:attribute>
        <xsl:attribute name="pgwide">1</xsl:attribute>
        <colspec> <xsl:attribute name="colnum">1</xsl:attribute><xsl:attribute name="colwidth">.3*</xsl:attribute></colspec>
        <colspec> <xsl:attribute name="colnum">2</xsl:attribute><xsl:attribute name="colwidth">.35*</xsl:attribute></colspec>
        <colspec> <xsl:attribute name="colnum">3</xsl:attribute><xsl:attribute name="colwidth">.35*</xsl:attribute></colspec>
        <thead>
          <row>
            <entry></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><white>Loss</white></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><white>Shift</white></paragraph></entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry><paragraph><xsl:value-of select="concat($lastbiennium,' Revenue Impact:')"/></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><LastRevLoss><xsl:value-of select="../LastRevLoss"/></LastRevLoss></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><LastRevShift><xsl:value-of select="../LastRevShift"/></LastRevShift></paragraph></entry>
          </row>
          <row>
            <entry><paragraph><xsl:value-of select="concat($curbiennium,' Revenue Impact:')"/></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><CurRevLoss><xsl:value-of select="../CurRevLoss"/></CurRevLoss></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><CurRevShift><xsl:value-of select="../CurRevShift"/></CurRevShift></paragraph></entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </xsl:template>
 
  <!-- builds the rev estimate table for Other Tax Programs (because PIT also has a total column, we use the choose statement to exclude PIT from following this template-->
  <xsl:template match="LastRevTotal">
    <xsl:choose>
      <xsl:when test="../TAXSORT &lt; 3">
      </xsl:when>
      <xsl:otherwise>
        <table>
      <tgroup>
        <xsl:attribute name="cols">2</xsl:attribute>
        <xsl:attribute name="pgwide">1</xsl:attribute>
        <colspec> <xsl:attribute name="colnum">1</xsl:attribute><xsl:attribute name="colwidth">.3*</xsl:attribute></colspec>
        <colspec> <xsl:attribute name="colnum">2</xsl:attribute><xsl:attribute name="colwidth">.7*</xsl:attribute></colspec>
        <thead>
          <row>
            <entry></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><white>Total</white></paragraph></entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry><paragraph><xsl:value-of select="concat($lastbiennium,' Revenue Impact:')"/></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><LastRevTotal><xsl:value-of select="../LastRevTotal"/></LastRevTotal></paragraph></entry>
          </row>
          <row>
            <entry><paragraph><xsl:value-of select="concat($curbiennium,' Revenue Impact:')"/></paragraph></entry>
            <entry><xsl:attribute name="align">center</xsl:attribute><paragraph><CurRevTotal><xsl:value-of select="../CurRevTotal"/></CurRevTotal></paragraph></entry>
          </row>
        </tbody>
      </tgroup>
    </table>
      </xsl:otherwise>
    </xsl:choose> 
  </xsl:template>
  
<!-- may want to add tab into each list item. If so, I can do so here-->
   <xsl:template match="li">
    <li>
        <paragraph>
        <xsl:apply-templates/>
        </paragraph>
    </li>
  </xsl:template>
 
    
  <!-- removes some weird formatting that comes out of the rich text format fields. NEEDS FIXED TO NOT REMOVE NESTED LISTS!!! -->
  <!--
  <xsl:template match="font"> 
    <xsl:apply-templates/>
  </xsl:template>
  -->
  
  <xsl:template match="div"> 
    <paragraph>
      <xsl:apply-templates 
                  select="node()[boolean(normalize-space(translate(., '&#160;', ' ')))]
                         |@*"/>
    </paragraph>
  </xsl:template>


  
  <!-- converts weird rtf formatting to a list format that FrameMaker can work with NEED to allow nested lists, still need to figure out how-->
  <xsl:template match="ul">
    <xsl:choose>
    <xsl:when test="child::*[1][self::ul]">
        <xsl:apply-templates/>
    </xsl:when>
    <xsl:otherwise>
    <unorderedList>
      <xsl:apply-templates/>
    </unorderedList>
    </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
    <!--does same for ordered lists-->
  <xsl:template match="ol">
    <xsl:choose>
    <xsl:when test="child::*[1][self::ol]">
        <xsl:apply-templates/>
    </xsl:when>
    <xsl:otherwise>
        <orderedList>
          <xsl:apply-templates/>
        </orderedList>
    </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <!-- try to configure second and third layer bulleted list-->
  
  <xsl:template match="list2">
    <ltwo>
      <xsl:apply-templates select = "list2"/>
    </ltwo>
  </xsl:template>
  
   <!--does same for ordered lists-->
  <xsl:template match="blockquote">
    <xsl:choose>
    <xsl:when test="child::*[1][self::blockquote]"> <!-- gets rid of blockquotes inside of blockquotes, which for some reason come out of Access RTF fields-->
        <xsl:apply-templates/>
    </xsl:when>
    <xsl:otherwise>
    <paragraph>
        <blockQuote>
          <xsl:apply-templates/>
        </blockQuote>
    </paragraph>
    </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  
  <!-- below drops a number of nodes that we do not need. Typically these were converted into attributes or moved to a different "level" in the tree, and we are removing the nodes that were in the old location. -->
  <xsl:template match="IntID"/>
  <xsl:template match="TaxSort"/>
  <xsl:template match="TaxType"/>
  <xsl:template match="Program"/>
  <xsl:template match="ExpType"/>
  <xsl:template match="ProgramSort"/>
  <xsl:template match="ExpTypeSort"/>
  <xsl:template match="fedconnect"/>
  <xsl:template match="CurRevPIT"/>
  <xsl:template match="LastRevCorp"/>
  <xsl:template match="CurRevCorp"/>
  <xsl:template match="CurRevLoss"/>
  <xsl:template match="LastRevShift"/>
  <xsl:template match="CurRevShift"/>
  <xsl:template match="CurRevTotal"/>
  <!-- <xsl:template match="blockquote"/> there may be a valid reason for these, if so we will need to take a closer look at this.-->
  <xsl:template match="ChapterText"/>
  <xsl:template match="SectionName"/>
  <xsl:template match="HeaderName"/>
  <xsl:template match="SectionLevel"/>
  
</xsl:stylesheet>

'''

xpath xslt xslt-3.0
1个回答
0
投票

我想知道您是否应该使用

htmlparse
函数一次将
Description
元素的内容转换为元素节点,其中一些是
div
,其中
font
子级具有转义的
<listX>
start 和
 </listX>
结束标签。

如果输入简单且常规,我会尝试使用嵌套

for-each-group group-starting-with/group-ending-with
将转义列表开始/结束标记转换为
listX
包装元素。

例如,要获取示例输入的一部分,您可以处理例如

<Description>
&lt;ul&gt;
 &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;The proposed facility is intended to operate for at least 10 years. &lt;/font&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;list2&amp;gt;&lt;/font&gt;&lt;/div&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;between July 1, 2011, and October 5, 2017, receive compensation (wages and benefits) at least 50 percent higher than the per capita personal income (PCPI) for the county at the time of the application, or at least equal to county PCPI while providing health insurance benefits, or,&lt;/font&gt;&lt;/li&gt;
 &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;since October 6, 2017 (HB 2066, 2017):&lt;/font&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;/list2&amp;gt;&lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;list3&amp;gt;&lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;(i) receive compensation meeting the above minimums or that is at least 30 percent more than county PCPI for locations outside any metropolitan statistical area, and&lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;(ii) (in all cases) receive an average annual wage at least equal to the then current average wage for the county. &lt;/font&gt;&lt;/div&gt;

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;lt;/list3&amp;gt;&lt;/font&gt;&lt;/div&gt;
</Description>

代码如下

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:dc="data:,dpc"
  exclude-result-prefixes="#all"
  xmlns:mf="http://example.com/mf"
  expand-text="yes">
  
  <xsl:function name="mf:wrap-lists" as="node()*">
    <xsl:param name="nodes" as="node()*"/>
    <xsl:param name="list-level" as="xs:integer"/>
    <xsl:for-each-group select="$nodes" group-starting-with="div[*[1][self::font[. = '&lt;' || 'list' || $list-level || '&gt;']]]">
      <xsl:choose>
        <xsl:when test="self::div[*[1][self::font[. = '&lt;' || 'list' || $list-level || '&gt;']]]">
          <xsl:for-each-group select="tail(current-group())" group-ending-with="div[*[1][self::font[. = '&lt;/' || 'list' || $list-level || '&gt;']]]">
            <xsl:choose>
              <xsl:when test="current-group()[last()][self::div[*[1][self::font[. = '&lt;/' || 'list' || $list-level || '&gt;']]]]">
                <xsl:element name="list{$list-level}">
                  <xsl:apply-templates select="current-group()[position() ne last()]"/>
                </xsl:element>
              </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:function>
  
  <xsl:import href="https://raw.githubusercontent.com/davidcarlisle/web-xslt/main/htmlparse/htmlparse.xsl"/>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:template match="Description">
    <xsl:copy>
      <xsl:sequence select="fold-left(2 to 3, dc:htmlparse(., '', false())!node(), function($n, $c) { mf:wrap-lists($n, $c) })"/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

并且会得到例如

<Description>
<ul>
 <li><font face="Times New Roman" color="black">The proposed facility is intended to operate for at least 10 years. </font></li>
</ul>

<list2>

<ul>
 <li><font face="Times New Roman" color="black">between July 1, 2011, and October 5, 2017, receive compensation (wages and benefits) at least 50 percent higher than the per capita personal income (PCPI) for the county at the time of the application, or at least equal to county PCPI while providing health insurance benefits, or,</font></li>
 <li><font face="Times New Roman" color="black">since October 6, 2017 (HB 2066, 2017):</font></li>
</ul>

</list2>

<list3>

<div><font face="Times New Roman" color="black">(i) receive compensation meeting the above minimums or that is at least 30 percent more than county PCPI for locations outside any metropolitan statistical area, and</font></div>

<div><font face="Times New Roman" color="black">(ii) (in all cases) receive an average annual wage at least equal to the then current average wage for the county. </font></div>

</list3>
</Description>

我希望这有助于解决部分“展开/封闭”问题。

© www.soinside.com 2019 - 2024. All rights reserved.