xslt 转换在 Altova 中有效,但在 python 中无效

xslt transformation works in Altova but not in python

我正在尝试使用 xslt 将一个 xml 转换为另一个 xml。下面是我正在使用的 xslt

  <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns="Apartments.AP.Mits20PropertyFinal"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                    xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
                    exclude-result-prefixes="msxsl var userCSharp"
                    xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp"
                    >
      <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:key name="myKey" match="ILS_Unit/Units/Unit" use="./Identification[@IDType='FloorplanID']/@IDValue"/> 
      <xsl:template match="/">
        <PhysicalProperty>
    <!--      <xsl:apply-templates select="PhysicalProperty/Management"/>
    -->      <xsl:apply-templates select="PhysicalProperty/Property"/>
        </PhysicalProperty>
      </xsl:template>
      <xsl:template match="Property">
        <Property>      
          <PropertyInfo>

              <xsl:element name="MITSID">
                <xsl:value-of select="./PropertyID/Identification[@IDRank='secondary']/@IDValue"/>
              </xsl:element>
              <xsl:element name="MarketingName">
                <xsl:value-of select="./PropertyID/MarketingName"/>
              </xsl:element>
              <xsl:element name="TotalUnits">

              </xsl:element>
              <xsl:element name="AddressLine1">
                <xsl:value-of select="./PropertyID/Address/AddressLine1"/>
              </xsl:element>
              <xsl:element name="City">
                <xsl:value-of select="./PropertyID/Address/City"/>
              </xsl:element>
              <xsl:element name="State">
                <xsl:value-of select="./PropertyID/Address/State"/>
              </xsl:element>
              <xsl:element name="Zip">
                <xsl:value-of select="./PropertyID/Address/PostalCode"/>
              </xsl:element>

          </PropertyInfo>


           <xsl:for-each select="./Floorplan">
           <Floorplan>
              <FloorplanID><xsl:value-of select="./@IDValue"/></FloorplanID>
              <FloorplanName><xsl:value-of select="./Name"/></FloorplanName>
                <!--This Unit count is Totals no of Units per floorplan-->
              <UnitCount><xsl:value-of select="./UnitCount"/></UnitCount>
               <Units>

               <xsl:variable name="floorplanid" select="./@IDValue"/>
               <xsl:for-each select="key('myKey',$floorplanid)">
               <Unit>
                  <UnitNum>
                   <xsl:value-of select="./MarketingName"/>
                  </UnitNum>

                   <xsl:if test="./UnitLeasedStatus='Not_Available'">
                   <UnitLeasedStatus>Occupied</UnitLeasedStatus> 
                  </xsl:if>
                   <xsl:if test="./UnitLeasedStatus='On_Notice'">
                   <UnitLeasedStatus>On Notice</UnitLeasedStatus> 
                  </xsl:if>
                  <xsl:if test="./UnitLeasedStatus='Available'">
                   <UnitLeasedStatus>Available</UnitLeasedStatus> 
                  </xsl:if>


                 </Unit>
                </xsl:for-each>
      </Units>
     </Floorplan>
           </xsl:for-each>

        </Property>
      </xsl:template>
    </xsl:stylesheet>

下面是示例 xml 文件

  <?xml version="1.0" encoding="utf-8"?>
    <PhysicalProperty>
        <Property>
            <PropertyID>
                <Identification IDValue="183dbed4-0101-4a85-954c-a4e8042d2819" IDRank="primary"/>
                <Identification IDValue="6458174" IDRank="secondary"/>
                <MarketingName>Westmount at London Park</MarketingName>
                <Website>http://www.westmountatlondonpark.com</Website>
                <Address AddressType="property">
                    <AddressLine1>14545 Bammel North Houston Road</AddressLine1>
                    <AddressLine2/>
                    <City>Houston</City>
                    <State>TX</State>
                    <PostalCode>77014</PostalCode>
                </Address>
            </PropertyID>
            <ILS_Identification ILS_IdentificationType="Apartment" RentalType="Unspecified"/>
            <Floorplan IDValue="171ad0f2-da57-45c0-9cf5-c61cfa26dd63" IDType="FloorplanID" IDRank="primary">
                <FloorplanType>Internal</FloorplanType>
                <Name>A1  </Name>
                <Comment/>
                <UnitCount>22</UnitCount>
                <UnitsAvailable>3</UnitsAvailable>
                <DisplayedUnitsAvailable>5</DisplayedUnitsAvailable>
                <Room RoomType="Bedroom">
                    <Count>1</Count>
                </Room>
                <Room RoomType="Bathroom">
                    <Count>1</Count>
                </Room>
                <SquareFeet Min="602" Max="602"/>
                <EffectiveRent Min="810" Max="830"/>
                <Deposit DepositType="Security Deposit">
                    <Amount>
                        <ValueRange Min="150" Max="150"/>
                    </Amount>
                </Deposit>
                <File FileID="e114a438-ee82-497d-8e04-6a5a8b2381ef" active="true">
                    <FileType>Floorplan</FileType>
                    <Caption/>
                    <Src>https://apollostore.blob.core.windows.net/londonpark/uploads/images/floorplans/a1.7a75909c-3362-409c-82c7-aa6c959f9c99.jpg</Src>
                    <Rank>999</Rank>
                </File>
            </Floorplan>
            <ILS_Unit>
                <ILS_Unit IDValue="be827564-6460-4af1-9644-3f6ffa225557" IDType="UnitID" IDRank="primary">
                    <Units>
                        <Unit>
                            <Identification IDValue="be827564-6460-4af1-9644-3f6ffa225557" IDType="UnitID" IDRank="primary"/>
                            <Identification IDValue="171ad0f2-da57-45c0-9cf5-c61cfa26dd63" IDType="FloorplanID" IDRank="primary"/>
                            <MarketingName>1901</MarketingName>
                            <UnitBedrooms>1</UnitBedrooms>
                            <UnitBathrooms>1</UnitBathrooms>
                            <UnitRent>765</UnitRent>
                            <UnitLeasedStatus>Not_Available</UnitLeasedStatus>
                            <FloorplanName>A1  </FloorplanName>
                        </Unit>
                    </Units>
                    <Comment/>
                    <EffectiveRent Min="765" Max="765"/>
                    <Deposit DepositType="Security Deposit">
                        <Amount>
                            <ValueRange Min="150" Max="150"/>
                        </Amount>
                    </Deposit>
                </ILS_Unit>
            </ILS_Unit>
        </Property>
    </PhysicalProperty>

转换使用 altova 工具工作正常,但在 python 中不起作用。 下面是我正在使用的 python 脚本。

from lxml import etree
import os
import glob
xslt = etree.parse("fl.xslt")
dom = etree.parse("f.xml",)

transform = etree.XSLT(xslt)


try:
    newdom = transform(dom)
    root = etree.parse(newdom)
    properties = root.findall("./Property")
    print(properties)

except Exception as e:
    print (e)
    for error in transform.error_log:
        print(error.message, error.line)
print(etree.tostring(newdom, pretty_print=True))

我正在尝试打印 属性 节点,我还尝试将结果写入 .xml 文件,但 returns 什么也没有。有人能说出问题是什么吗? 令人惊讶的是,它在 Altova 中运行良好。

下面是抛出的错误。

 line 53, in <module>
    root = etree.parse(newdom)
  File "src\lxml\etree.pyx", line 3519, in lxml.etree.parse
  File "src\lxml\parser.pxi", line 1862, in lxml.etree._parseDocument
TypeError: cannot parse from 'lxml.etree._XSLTResultTree'

具体错误与 XSLT 无关,而是您尝试 parse 结果。与 Python 的内置 xml.etree 一样,lxml 中的 parse function of lxml.etree requires a file-like object. However, the result from an XSLT 转换是 一个 ElementTree 对象,您可以直接 运行 任何 XML DOM 调用,例如 findalliterfind

因此,只需删除 parse 行。此外,因为您有一个默认名称空间,请考虑为访问节​​点分配一个临时前缀。此外,请考虑 lxml 中的 xpath

newdom = transform(dom)

properties = newdom.findall("./doc:Property", namespaces={'doc': 'Apartments.AP.Mits20PropertyFinal'})
print(properties)
# [<Element {Apartments.AP.Mits20PropertyFinal}Property at 0x136b2f94b08>]

properties = newdom.xpath("./doc:Property", namespaces={'doc': 'Apartments.AP.Mits20PropertyFinal'})
print(properties)
# [<Element {Apartments.AP.Mits20PropertyFinal}Property at 0x136b2f94b08>]

输出

print(etree.tostring(newdom, pretty_print=True).decode("utf-8"))

# <PhysicalProperty xmlns="Apartments.AP.Mits20PropertyFinal">
#   <Property>
#     <PropertyInfo>
#       <MITSID>6458174</MITSID>
#       <MarketingName>Westmount at London Park</MarketingName>
#       <TotalUnits/>
#       <AddressLine1>14545 Bammel North Houston Road</AddressLine1>
#       <City>Houston</City>
#       <State>TX</State>
#       <Zip>77014</Zip>
#     </PropertyInfo>
#     <Floorplan>
#       <FloorplanID>171ad0f2-da57-45c0-9cf5-c61cfa26dd63</FloorplanID>
#       <FloorplanName>A1  </FloorplanName>
#       <UnitCount>22</UnitCount>
#       <Units>
#        <Unit>
#           <UnitNum>1901</UnitNum>
#           <UnitLeasedStatus>Occupied</UnitLeasedStatus>
#         </Unit>
#       </Units>
#     </Floorplan>
#   </Property>
# </PhysicalProperty>