Python 使用函数时如何改善eXSLT性能问题 TL;博士:

Python 使用函数时如何改善eXSLT性能问题 TL;博士:,python,xml,xslt,saxon,Python,Xml,Xslt,Saxon,似乎运行eXSLT要比XSLT2中的eXSLT慢得多。(7分钟对18小时) 下面我解释我的问题,用eXSLT和XSLT2写下相同转换的两个实现 当然,引擎是不同的,对于XSLT2我使用SaxonHE,对于eXSLT我使用python和lxml 最后,我请求帮助提高eXSLT部分的速度,因为我更喜欢使用python而不是Java 我必须将一个大的(~200k tier 1 elements)XML转换为csv 我有两个实现: 一个使用python,所以下面是libxml,我使用eXSL 另一个

似乎运行eXSLT要比XSLT2中的eXSLT慢得多。(7分钟对18小时)

下面我解释我的问题,用eXSLT和XSLT2写下相同转换的两个实现

当然,引擎是不同的,对于XSLT2我使用SaxonHE,对于eXSLT我使用python和lxml

最后,我请求帮助提高eXSLT部分的速度,因为我更喜欢使用python而不是Java


我必须将一个大的(~200k tier 1 elements)XML转换为csv

我有两个实现:

  • 一个使用python,所以下面是libxml,我使用eXSL
  • 另一个使用SaxonHE,所以我使用XSL2转换
由于在编写CSV时,即使元素没有值,也必须打印分隔符,因此我采用了这种方法:

我创建了两个函数:

myf:printElement
,它接收一个元素和一个数字,该数字表示元素为空时必须写入的分隔符数

myf:printAttr
,它接收一个属性,并将其与分隔符一起打印

如果我还将分隔符定义为:

<xsl:param name="delim" select="','"/>
关于这一点,请注意:

  • Child2可以在Tier1下重复,但只有一组给定的type值,不能重复

  • 元素中也没有文本,这使得使用这两个函数的方法涵盖了我可能遇到的所有情况。尽管printAttr可能也适用于文本节点

  • 我添加了列名以便于阅读。在代码中,我在开始时添加了它,一个包含eXSLT的内部节点集,一个包含XSLT2的简单字符串数组

那么,现在的问题是: 正如我在开始时所说的,我必须运行转换到一个巨大的文件,其中包含超过200k的Tier1元素

  • 撒克逊人需要7分钟
  • 使用Python时,需要18小时
两个转换脚本/程序都执行相同的操作:

  • 打开文件
  • 打开XSLT
  • 将后者应用于前者
  • 保存结果
  • 我知道我所说的是转换引擎的不同实现,但这种差异太明显了,不能因为这个。 测试同一个引擎的唯一方法是在Saxon PE或Saxon EE下使用eXSLT,因为它在Saxon HE中不可用。 当然,python中没有XSLT2实现

    我想知道为什么python版本花费的时间太长。这是eXSLT的固有使用吗?或者有什么方法可以改进这一点吗?

    当然,这是一个示例XML,真正的XML包含更多的元素,而且实际上更复杂

    这是一个更大项目的一部分,我不想仅仅依靠JVM来实现这一点,但是,差别如此之大,以至于现在,Python不是一个选项


    谢谢

    在我看来,你似乎对这个问题的处理过度了

    下面是简单的XSLT1.0转换

    <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="text" encoding="utf-8" />
    
      <xsl:template match="/root">
        <xsl:text>T1_attr1,T1_attr2,C2_t1,C2_t2,C2_t3,C3_a,C4_Month,C4_Day,C4_Average</xsl:text>
        <xsl:apply-templates select="Tier1" />
      </xsl:template>
    
      <xsl:template match="Tier1">
        <xsl:text>&#xA;</xsl:text>
        <xsl:value-of select="@attr1" />                   <xsl:text>,</xsl:text>
        <xsl:value-of select="@attr2" />                   <xsl:text>,</xsl:text>
        <xsl:value-of select="Child2[@type = '1']/@val" /> <xsl:text>,</xsl:text>
        <xsl:value-of select="Child2[@type = '2']/@val" /> <xsl:text>,</xsl:text>
        <xsl:value-of select="Child2[@type = '3']/@val" /> <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/@a" />                <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/Child4/@Month" />     <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/Child4/@Day" />       <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/Child4/@Average" />
      </xsl:template>
    </xsl:transform>
    
    
    T1_属性1、T1_属性2、C2_T1、C2_t2、C2_t3、C3_a、C4_月、C4_日、C4_平均值
    
    ;
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    
    适用于

    <root>
      <Tier1 attr1="A" attr2="B">
      </Tier1>
      <Tier1 attr1="C" attr2="D">
        <Child2 type="1" val="ABC" />
        <Child2 type="3" val="123" />
      </Tier1>
      <Tier1 attr1="E" attr2="F">
        <Child2 type="2" val="pancakes" />
        <Child2 type="1" val="42" />
        <Child3 a="H">
            <Child4 Month="JUN" Day="3" Average="1200" />
        </Child3>
      </Tier1>
    </root>
    
    
    
    产生

    T1_attr1,T1_attr2,C2_t1,C2_t2,C2_t3,C3_a,C4_Month,C4_Day,C4_Average A,B,,,,,,, C,D,ABC,,123,,,, E,F,42,pancakes,,H,JUN,3,1200 T1_属性1、T1_属性2、C2_T1、C2_t2、C2_t3、C3_a、C4_月、C4_日、C4_平均值 A、 B,,,,,,, C、 美国广播公司广播公司,,,, E、 F,42,煎饼,H,6月,31200
    真的是你的代码吗?规范未将任何
    显示为
    属性。当删除那些
    as
    属性并在样式表中使用
    version=“1.0”
    时,您是否获得了更好的性能(假设您当前有
    version=“2.0”
    ,否则我根本看不出您的代码片段为什么会工作)?是的,它可以工作,ofc version=“1.0”用于eXSLT,而“2.0”用于XSLT2。无论如何,我将尝试将
    作为
    删除,这可能是我从xslt2转换为eXSLT时留下的。奇怪的是,我没有得到任何错误。而且,在Pytom下运行XSLT2是不可行的……当出现
    version=“2.0”
    样式表时,XSLT 1.0处理器应该尝试运行它。至于性能问题,如果在不使用Python的情况下(从命令行)使用xsltproc/libxslt,会发生什么情况?是否也需要那么长的时间?我还认为您可以简单地像
    那样对模板
    进行编码,并使用例如
    而不是例如
    。但显然,正确的方法是分析Python/libxslt代码,看看在哪里花时间来改进这些部分。否则很难说为什么要花这么长时间。是的,我可能对干燥原理有点偏见。我不喜欢有这么多重复的逗号,让元素在每一场比赛中分开对我来说似乎很好。但我不习惯于编写XSLT,也不习惯于应用在这个领域没有多大意义的标准。谢谢@Trompa此模板在几秒钟内就可以处理20MB的XML(~200k
    元素,如图所示)。@Trompa DRY在XSLT中确实有意义,但有时使用内衬是最快的方式(我可能会补充说,也是最可读的方式)。它在您的环境中表现如何?(尝试Saxon和lxml)我正在做一个新的转换,以在原始文件中测试它。我会发布结果,但是Saxon和lxml之间的差异让人感觉很奇怪。好了,终于得到了结果。这是一个166M文件:PYT中的新XSLT:
    23.52s用户0.76s系统97%cpu 24.786总计
    JVA中的新XSLT:
    78.86s用户0.96s系统407%cpu 19.606总计
    JVA中的旧XSLT2:
    76.88s用户0.78s系统460%cpu 16.853总计
    ,因此,我猜函数的使用会增加很多开销。现在的差别是可以忽略的。谢谢!
    <xsl:param name="break" select="'&#xA;'"/>
    <xsl:template match="/">
         <xsl:apply-templates select="root/Tier1"/>`
    </xsl:template>
    <xsl:template match="Tier1">
        <xsl:value-of select="myf:printAttr(@attr1)"/>
        <xsl:value-of select="myf:printAttr(@attr2)"/>
        <xsl:value-of select="myf:printAttr(Child2[@type='1']/@val)"/>
        <xsl:value-of select="myf:printAttr(Child2[@type='2']/@val)"/>
        <xsl:value-of select="myf:printAttr(Child2[@type='3']/@val)"/>
        <xsl:apply-templates/>
        <!-- line break after each Tier1 -->
        <xsl:if test="following-sibling::*">
            <xsl:value-of select="$break"/>
        </xsl:if>
    </xsl:template>
    <xsl:template match="Child3">
        <xsl:value-of select="myf:printAttr(@a)"/>
        <xsl:value-of select="ama:printElement(Child4,3)"/>
    </xsl:template>
    <xsl:template match="Child4">
        <xsl:value-of select="myf:printAttr(@Day)"/>
        <xsl:value-of select="myf:printAttr(@Month)"/>
        <!-- We dont want comma after last element-->
        <xsl:value-of select=@Average/>
    </xsl:template>
    
    T1_attr1, T1_attr2, C2_t1, C2_t2, C2_t3, C3_a, C4_Mont, C4_Day, C4_Average
    A,B,,,,,,,
    C,D,ABC,,123,,,,
    E,F,42,pancakes,,H,JUN,3,1200
    
    <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="text" encoding="utf-8" />
    
      <xsl:template match="/root">
        <xsl:text>T1_attr1,T1_attr2,C2_t1,C2_t2,C2_t3,C3_a,C4_Month,C4_Day,C4_Average</xsl:text>
        <xsl:apply-templates select="Tier1" />
      </xsl:template>
    
      <xsl:template match="Tier1">
        <xsl:text>&#xA;</xsl:text>
        <xsl:value-of select="@attr1" />                   <xsl:text>,</xsl:text>
        <xsl:value-of select="@attr2" />                   <xsl:text>,</xsl:text>
        <xsl:value-of select="Child2[@type = '1']/@val" /> <xsl:text>,</xsl:text>
        <xsl:value-of select="Child2[@type = '2']/@val" /> <xsl:text>,</xsl:text>
        <xsl:value-of select="Child2[@type = '3']/@val" /> <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/@a" />                <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/Child4/@Month" />     <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/Child4/@Day" />       <xsl:text>,</xsl:text>
        <xsl:value-of select="Child3/Child4/@Average" />
      </xsl:template>
    </xsl:transform>
    
    <root>
      <Tier1 attr1="A" attr2="B">
      </Tier1>
      <Tier1 attr1="C" attr2="D">
        <Child2 type="1" val="ABC" />
        <Child2 type="3" val="123" />
      </Tier1>
      <Tier1 attr1="E" attr2="F">
        <Child2 type="2" val="pancakes" />
        <Child2 type="1" val="42" />
        <Child3 a="H">
            <Child4 Month="JUN" Day="3" Average="1200" />
        </Child3>
      </Tier1>
    </root>
    
    T1_attr1,T1_attr2,C2_t1,C2_t2,C2_t3,C3_a,C4_Month,C4_Day,C4_Average A,B,,,,,,, C,D,ABC,,123,,,, E,F,42,pancakes,,H,JUN,3,1200