python 2.7,xml,beautifulsoup4:只返回匹配的父标签
问题描述:
我想解析一些XML,但遇到问题时强制它只选择请求标记,如果它是父标记。例如,我的XML的部分是:python 2.7,xml,beautifulsoup4:只返回匹配的父标签
<Messages>
<Message ChainCode="LI" HotelCode="5501" ConfirmationID="5501">
<MessageContent>
<OTA_HotelResNotifRQ TimeStamp="2014-01-24T21:02:43.9318703Z" Version="4" ResStatus="Book">
<HotelReservations>
<HotelReservation>
<RoomStays>
<RoomStay MarketCode="CC" SourceOfBusiness="CRS">
<RoomRates>
<RoomRate EffectiveDate="2014-02-04" ExpireDate="2014-02-06" RoomTypeCode="12112" NumberOfUnits="1" RatePlanCode="RAC">
<Rates>
<Rate EffectiveDate="2014-02-04" ExpireDate="2014-02-06" RateTimeUnit="Day" UnitMultiplier="3">
<Base AmountBeforeTax="749.25" CurrencyCode="USD" />
<Total AmountBeforeTax="749.25" CurrencyCode="USD" />
</Rate>
</Rates>
</RoomRate>
</RoomRates>
<Total AmountBeforeTax="2247.75" CurrencyCode="USD">
<Taxes Amount="0.00" />
</Total>
</RoomStay>
</RoomStays>
</HotelReservation>
</HotelReservations>
</OTA_HotelResNotifRQ>
</MessageContent>
</Message>
</Messages>
我已经得到了整个事情解析我是如何将其与“总”标签的除外。
我想要得到总标签:
<Total AmountBeforeTax="2247.75" CurrencyCode="USD">
<Taxes Amount="0.00" />
</Total>
发生了什么事,是它的中返回的“总”标签是RoomRates的孩子\ RoomRate \价格\率。我试图弄清楚如何指定它来返回RoomStays \ RoomStay \ Total标记。我目前拥有的是:
soup = bs(response, "xml")
messages = soup.find_all('Message')
for message in messages:
hotel_code = message.get('HotelCode')
reservations = message.find_all('HotelReservation')
for reservation in reservations:
uniqueid_id = reservation.UniqueID.get('ID')
uniqueid_idcontext = reservation.UniqueID.get('ID_Context')
roomstays = reservation.find_all('RoomStay')
for roomstay in roomstays:
total = roomstay.Total
任何想法如何指定确切的标签我试图拉?如果有人想知道for循环,那是因为通常会有多个“Message”,“Hotel Reservation”,“Room Stay”等标签,但我已经将它们移除以仅显示一个。有时候可能会有多个Rate \ Rates标签,所以我不能要求它给我第二个“Total”标签。
希望我已经解释了这一点。
答
有时候也可能有多个Rate \ Rates标签,所以我不能要求它给我第二个“Total”标签。
为什么不只是遍历所有Total
标签并跳过那些没有Taxes
孩子的标签?
reservations = message.find_all('HotelReservation')
for reservation in reservations:
totals = reservation.find_all('Total')
for total in totals:
if total.find('Taxes'):
# do stuff
else:
# these aren't the totals you're looking for
如果你更一般要消除那些没有子节点,你可以做以下任一:
if next(total.children, None):
# it's a parent of something
if total.contents:
# it's a parent of something
,或者你可以use a function instead of a string as your filter:
total = reservation.find(lambda node: node.name == 'Total' and node.contents)
或者你可以看看其他方式来找到这个标签:它是一个直接的孩子RoomStay
,而不仅仅是一个后代;它不是Rate
的后代;它是RoomStay
下的最后一个Taxes
后代;所有这些都可以轻松完成。
话虽这么说,这似乎是对的XPath一个完美的工作,这BeautifulSoup
不支持,但ElementTree
和lxml
做...
忘了提的是,“税”孩子不会永远存在,所以不幸的是,我不认为这两种解决方案都可以工作:/但我会尝试查看ElementTree和LXML。 – crookedleaf
@crookedleaf:那么你想要什么规则呢?不管它是什么,你都可以写 - 我展示了如何写一个备选方案,并列出了其他三种可能的备选方案,这些备选方案同样简单。但是在你编码之前你必须知道你想要哪一个。 – abarnert
@abarnet其实,没有注意到你的第二个解决方案有两个不同的解决方案,第三个解决方案不在我最初看的时候。基本上,我试图把$ 2247.75作为一个变量。我最初希望的是做一些类似“total = roomstay.Total”的东西。get('AmountBeforeTaxes')“,如果不是之前的”Total“标签,它会给我想要达到的内容,我会尝试其他两种解决方案。 – crookedleaf