Python 使用XPath解析定义列表的最佳方法是什么?

Python 使用XPath解析定义列表的最佳方法是什么?,python,xslt,xpath,Python,Xslt,Xpath,我使用Python+xPath解析一些HTML,但解析定义列表时遇到问题。例如: 第一节 孩子一 孩子一 第二节 孩子二 我想将其转换为如下输出: {'Section One':['Child One','Child One.2'],'Section Two':['Child Two']} 但是我有困难,因为结构的方式不同,在输出中没有相同的层次结构 感谢一个没有xpath的解决方案,如果您正在使用xpath,那么您可能已经在使用lxml了: from collections import

我使用Python+xPath解析一些HTML,但解析定义列表时遇到问题。例如:

第一节 孩子一 孩子一 第二节 孩子二

我想将其转换为如下输出: {'Section One':['Child One','Child One.2'],'Section Two':['Child Two']}

但是我有困难,因为结构的方式不同,在输出中没有相同的层次结构


感谢一个没有xpath的解决方案,如果您正在使用xpath,那么您可能已经在使用lxml了:

from collections import defaultdict
from lxml import etree

dl = etree.fromstring('''<dl>
<dt>Section One</dt>
<dd>Child one</dd>
<dd>Child one.2</dd>
<dt>Section Two</dt>
<dd>Child two</dd>
</dl>''')

result = defaultdict(list)
for dt in dl.findall('dt'):
    for child in dt.itersiblings(): # iterate over following siblings
        if child.tag != 'dd':
            break # stop at the first element that is not a dd
        result[dt.text].append(child.text)

print dict(result)
我能想到的任何xpath解决方案都比这更糟糕,似乎一个单一表达式xpath 1.0解决方案(如果可能的话)都很难编写和理解

下面是一个简单的XSLT 1.0解决方案:


说明:xsl:key被定义并用于捕获dt和紧接其后的同级dt元素之间的1->many关系。

您真的需要使用XPath吗?您可以迭代文档并获得所需的结果。您需要的是转换,XSLT和输出方法文本就足够了。XPath 1.0数据类型是节点集无序和唯一、数字双精度、字符串和布尔值。这些都不是您想要的结构化数据类型。您需要迭代dt元素,然后迭代同级dd元素,无论您是使用XPath还是任何其他DOM API选择元素。不错,但我理解原始问题的输出是python字典,而不是确切的文字输出。@Steven:您可能是对的。OP说我想把它转换成一个输出,比如。。。这正是我给他的。如果需要其他东西,他仍然可以使用我的解决方案中的想法,或者使他的问题更具体,然后我可以再次向他提供想要的答案。他甚至可以使用这个解决方案来生成Python源代码。+1-比起XSLT提出的替代方案,他更喜欢这个优雅的解决方案。谢谢史蒂文,我已经很好地利用了它。
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kFollowing" match="dd"
      use="generate-id(preceding-sibling::dt[1])"/>

 <xsl:template match="dl">
  { <xsl:apply-templates select="dt"/> }
 </xsl:template>

 <xsl:template match="dt">
  <xsl:text/>'<xsl:value-of select="."/>' : [ <xsl:text/>
   <xsl:apply-templates select=
       "key('kFollowing', generate-id())"/>
   <xsl:text> ]</xsl:text>
   <xsl:if test="not(position()=last())">, </xsl:if>
 </xsl:template>

 <xsl:template match="dd">
  <xsl:text/>'<xsl:value-of select="."/>'<xsl:text/>
   <xsl:if test="not(position()=last())">, </xsl:if>
 </xsl:template>
</xsl:stylesheet>
<dl>
    <dt>Section One</dt>
    <dd>Child one</dd>
    <dd>Child one.2</dd>
    <dt>Section Two</dt>
    <dd>Child two</dd>
</dl>
  { 'Section One' : [ 'Child one', 'Child one.2' ], 'Section Two' : [ 'Child two' ] }