Добавить существующий узел элемента к узлу над ним, используя XSLT - PullRequest
0 голосов
/ 30 октября 2019

У меня есть следующее XML содержимое файла, которое я преобразую, используя lxml и XSLT.

contents.xml

<division id="ch.3-pt.1-div.4" guid="_172f071b-3e58-4780-9764-486f8ef6105c" affected.by.uncommenced="0" numbering.style="manual">
    <no>Division 4</no>
    <heading id="ch.3-pt.1-div.4-he" guid="_7674f8f8-89f8-4947-8457-36064bf4d157">Clinical waste disposal</heading>
    <clause id="sec.20" guid="_3b10e1a6-5526-4655-85f6-90dee5425aee" affected.by.uncommenced="0" spent.amends="0" provision.type="other">
        <no>20</no>
        <heading id="sec.20-he" guid="_5ab98572-56f2-4c22-8c1c-b1274f9cd6a2">Untreated clinical waste disposal</heading>
        <subclause id="sec.20-ssec.1" guid="_c3831668-e2f1-4ba2-95bd-a41d0b6e7973" affected.by.uncommenced="0" provision.type="other">
            <no>(1)</no>
            <block>
                <txt break.before="0">A person must not deliver untreated clinical waste to a facility for disposal under <intref refid="sch.2" target.guid="_d1f92e33-15ef-42ef-ae13-4f6d916109e0" check="valid">schedule&#160;2</intref>, <intref refid="sch.2-sec.60" target.guid="_dab3fb38-8f7b-479c-99ee-caba191c3cf2" check="valid">section&#160;60</intref><intref refid="sch.2-sec.60-ssec.1" target.guid="_b8b31412-9d9f-4fd4-82e4-74d6eb6b0d1b" check="valid">(1)</intref><intref refid="sch.2-sec.60-ssec.1-para1.b" target.guid="_a2af180c-2fe6-42c7-ae0e-299a693fd5ae" check="valid">(b)</intref> unless the waste was generated in a scheduled area.</txt>
            </block>
            <penalty id="sec.20-ssec.1-pen" guid="_0fb13eb2-cccb-4022-9abf-4309d0132ed5">
                <block>
                <txt break.before="1">Maximum penalty&#8212;20 penalty units.</txt>
                </block>
            </penalty>
        </subclause>
    </clause>
</division>

contents.xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0/WD17" xmlns:date="http://exslt.org/dates-and-times" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
   <xsl:output method="xml" indent="yes" encoding="UTF-8" />
   <xsl:template match="/">
      <akomaNtoso xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://docs.oasis-open.org/legaldocml/ns/akn/3.0 http://docs.oasis-open.org/legaldocml/akn-core/v1.0/cos01/part2-specs/schemas/akomantoso30.xsd">
         <xsl:apply-templates />
      </akomaNtoso>
   </xsl:template>

   <!-- Copy all nodes but strip attributes (modified identity transform) -->
   <xsl:template match="node()">
      <xsl:copy>
         <xsl:apply-templates />
      </xsl:copy>
   </xsl:template>

   <xsl:template match="division/clause/block">
      <xsl:choose>
         <xsl:when test="definition">
            <wrapUp>
               <xsl:apply-templates select="definition" />
            </wrapUp>
         </xsl:when>
         <xsl:otherwise>
            <xsl:apply-templates />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <!-- THIS IS THE PART I EXPECT TO WORK FOR ME BUT IT DOES NOT -->
   <!-- Match all penalty or blocks under subclause and put them in a content node -->
   <xsl:template match="clause/subclause/*[name()='block' or name()='penalty']">
      <xsl:choose>
         <xsl:when test="table">
            <wrapUp>
               <xsl:apply-templates select="table" />
            </wrapUp>
         </xsl:when>
         <xsl:otherwise>
            <xsl:apply-templates /> <!-- THIS DOES NOT WORK -->
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <!-- Match all blocks after clause/[no,heading] but not blocks with lists as 2nd nodes -->
   <xsl:template match="//clause[heading[1]]/block[name(*[2]) != 'list']">
      <content>
         <xsl:apply-templates />
      </content>
   </xsl:template>
   <xsl:template match="subclause">
      <subsection>
         <xsl:attribute name="eId">
            <xsl:value-of select="@id" />
         </xsl:attribute>
         <xsl:apply-templates />
      </subsection>
   </xsl:template>

   <!-- Match all blocks with first element as txt and second element is not list -->
   <xsl:template match="//subclause/block[txt[1] and name(*[2]) != 'list' and name(*[2]) != 'deflist']">
      <content>
         <xsl:apply-templates />
      </content>
   </xsl:template>
</xsl:stylesheet>

Моя проблема в том, что когда я запускаю следующее преобразование, он не добавляет узел penalty внутри block над ним.

То, что я получаю:

<?xml version="1.0" encoding="UTF-8"?>
<akomaNtoso xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0" xmlns:date="http://exslt.org/dates-and-times" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://docs.oasis-open.org/legaldocml/ns/akn/3.0 http://docs.oasis-open.org/legaldocml/akn-core/v1.0/cos01/part2-specs/schemas/akomantoso30.xsd">
  <division xmlns="">
    <no>Division 4</no>
    <heading>Clinical waste disposal</heading>
    <clause>
      <no>20</no>
      <heading>Untreated clinical waste disposal</heading>
      <subsection xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0/WD17" eId="sec.20-ssec.1">
        <no xmlns="">(1)</no>
        <content>
          <txt xmlns="">
            A person must not deliver untreated clinical waste to a facility for disposal under
            <intref>schedule 2</intref>
            ,
            <intref>section 60</intref>
            <intref>(1)</intref>
            <intref>(b)</intref>
            unless the waste was generated in a scheduled area.
          </txt>
        </content>
        <!-- THIS IS WHERE MY PROBLEM IS, IT IS OUTSIDE content ABOVE -->
        <block xmlns="">
          <txt>Maximum penalty—20 penalty units.</txt>
        </block>
      </subsection>
    </clause>
  </division>
</akomaNtoso>

Что я ожидаю, так это:

<?xml version="1.0" encoding="UTF-8"?>
<akomaNtoso xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0" xmlns:date="http://exslt.org/dates-and-times" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://docs.oasis-open.org/legaldocml/ns/akn/3.0 http://docs.oasis-open.org/legaldocml/akn-core/v1.0/cos01/part2-specs/schemas/akomantoso30.xsd">
  <division xmlns="">
    <no>Division 4</no>
    <heading>Clinical waste disposal</heading>
    <clause>
      <no>20</no>
      <heading>Untreated clinical waste disposal</heading>
      <subsection xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0/WD17" eId="sec.20-ssec.1">
        <no xmlns="">(1)</no>
        <content>
          <txt xmlns="">
            A person must not deliver untreated clinical waste to a facility for disposal under
            <intref>schedule 2</intref>
            ,
            <intref>section 60</intref>
            <intref>(1)</intref>
            <intref>(b)</intref>
            unless the waste was generated in a scheduled area.
          </txt>
         <!-- THIS SHOULD BE INSIDE THE content BLOCK LIKE THIS AFTER TRANSFORMATION COS penalty IS TRANSFORMED TO content-->
         <block xmlns="">
          <txt>Maximum penalty—20 penalty units.</txt>
        </block>
        </content>
      </subsection>
    </clause>
  </division>
</akomaNtoso>

Код, который я запускаю:

main.py

from lxml import etree


def transform_xml(tree, xslt_path):
    """Transforms an xml tree given an xslt."""
    try:
        transformer = etree.XSLT(etree.parse(xslt_path))
        tree = transformer(tree)
        return tree, None
    except (etree.XSLTParseError, etree.XMLSyntaxError) as error:
        return None, f"{error}"


if __name__ == "__main__":
    tree = """
    <division id="ch.3-pt.1-div.4" guid="_172f071b-3e58-4780-9764-486f8ef6105c" affected.by.uncommenced="0" numbering.style="manual">
        <no>Division 4</no>
        <heading id="ch.3-pt.1-div.4-he" guid="_7674f8f8-89f8-4947-8457-36064bf4d157">Clinical waste disposal</heading>
        <clause id="sec.20" guid="_3b10e1a6-5526-4655-85f6-90dee5425aee" affected.by.uncommenced="0" spent.amends="0" provision.type="other">
            <no>20</no>
            <heading id="sec.20-he" guid="_5ab98572-56f2-4c22-8c1c-b1274f9cd6a2">Untreated clinical waste disposal</heading>
            <subclause id="sec.20-ssec.1" guid="_c3831668-e2f1-4ba2-95bd-a41d0b6e7973" affected.by.uncommenced="0" provision.type="other">
            <no>(1)</no>
            <block>
                <txt break.before="0">A person must not deliver untreated clinical waste to a facility for disposal under <intref refid="sch.2" target.guid="_d1f92e33-15ef-42ef-ae13-4f6d916109e0" check="valid">schedule&#160;2</intref>, <intref refid="sch.2-sec.60" target.guid="_dab3fb38-8f7b-479c-99ee-caba191c3cf2" check="valid">section&#160;60</intref><intref refid="sch.2-sec.60-ssec.1" target.guid="_b8b31412-9d9f-4fd4-82e4-74d6eb6b0d1b" check="valid">(1)</intref><intref refid="sch.2-sec.60-ssec.1-para1.b" target.guid="_a2af180c-2fe6-42c7-ae0e-299a693fd5ae" check="valid">(b)</intref> unless the waste was generated in a scheduled area.</txt>
            </block>
            <penalty id="sec.20-ssec.1-pen" guid="_0fb13eb2-cccb-4022-9abf-4309d0132ed5">
                <block>
                <txt break.before="1">Maximum penalty&#8212;20 penalty units.</txt>
                </block>
            </penalty>
            </subclause>
        </clause>
    </division>
    """
    tree = etree.XML(tree)

    xslt_path = "xslt/convert.xslt"
    tree, error = transform_xml(tree, xslt_path)
    print(tree)
    print(error)

Я довольноновичок в XSLT, как мне этого добиться?

...