2012-03-01 4 views
4

Как я выбираю все (все возможные узлы) между 1-м и вторым h2? Там может быть n узлов между ними, и может быть m h2 теги.Как выбрать все элементы между двумя узлами с помощью XPath

Узлы не обязательно будут содержаться в HTML-элементе, поэтому селектор может просто захватить их все.

<html> 
<h2>asdf</h2> 
<p>good stuff 1</p> 
<p>good stuff 2</p> 
<p>good <a href="#">asdf</a>stuff n...</p> 
<h2>qwer</h2> 
<p>test2</p> 
<h2>dfgh</h2> 
<p>test2</p> 
</html> 

Я просто мочу ноги с помощью XPath. Пожалуйста, помогите моему новичку задать вопрос :)

Большое спасибо!

+0

это недопустимый xml –

+0

Почему? он хорошо сформирован как минимум –

ответ

4

Одно из выражений XPath, который выбирает элементы разыскиваемых является:

/*/h2[1] 
     /following-sibling::p 
     [count(. | /*/h2[2]/preceding-sibling::p) 
     = 
     count(/*/h2[2]/preceding-sibling::p) 
     ] 

В общем, в таких случаях можно использовать формулу Kayessian для множества пересечения:

$ns1[count(.|$ns2) = count($ns2)] 

выражение XPath выбирает Это все узлы, которые принадлежат как к nodesets $ns1 и $ns2.

Если вы хотите получить все узлы между двумя заданными узлами $ n1 и $ n2, это пересечение двух узлов: $n1/following-sibling::node() и $n2/preceding-sibling::node().

Просто замените это выражение на формулу Kayessian, и у вас есть требуемое выражение XPath.

В XPath 2.0, конечно, можно было бы использовать оператор << или >>, что-то вроде:

/*/h2[1]/following-sibling::p[. << /*/h2[1]/] 
+0

Спасибо за указание на ошибку моего ответа: я не читал образец XML достаточно хорошо, чтобы понять, что происходит. –

+0

@ ZacharyYoung: Добро пожаловать. –

+0

Можно ли заменить p звездочкой, чтобы получить все между h2s, даже если они не находятся в p-тегах? @DimitreNovatchev – Hoppe

1

Не уверен, XPath, но у вас есть тег C# 4.0, так что следующий код делает работу:

XElement.Parse(xml) 
       .Element("h2") 
       .ElementsAfterSelf() 
       .TakeWhile(n => n.Name != "h2") 
       .ToList() 
0

Что-то, как это должно работать (не использует XPath, хотя)

XmlReader reader = XmlReader.Create(new StringReader(xmlString)); 

    if (reader.ReadToDescendant("h2")) 
    { 
    reader.Skip(); 

    while (reader.Name != "h2") 
    {   
     //Handle nodes 
     reader.Read(); 
    } 
    } 
0

я знаю, что это не рабочий пример, но почти нет,

все, что вам действительно нужно сделать, это исправить ошибки синтаксиса и, возможно, исправить рекурсивные объекты.

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="@* | node()"> 
    <xsl:call-template name="tmpMatchNode"> 
     <xsl:with-param name="indx" select="0"/> 
     <xsl:with-param name="self" select="node()"/> 
    </xsl:call-template> 
    </xsl:template> 
    <xsl:template name="tmpMatchNode" > 
    <xsl:variable name="indx" /> 
    <xsl:variable name="self"/> 

    <xsl:element name="name($self[index])"> 
     <xsl:value-of select="$self[$indx]"/> 
    </xsl:element> 
    <xsl:choose> 
     <xsl:when test="$self[$indx+1]:name() != 'H2'"> 
     <xsl:call-template name="tmpMatchNode"> 
      <xsl:with-param name="indx" select="$indx +1"/> 
      <xsl:with-param name="self" select="$self"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:when test="$self[$indx]:name() = 'H2'"> 
     <xsl:call-template name="tmpMatchNode"> 
      <xsl:with-param name="indx" select="$indx +1"/> 
      <xsl:with-param name="self" select="$self"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:comment>DO NOTHING HERE AS WE HAVE NOTHING TO DO</xsl:comment> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 
Смежные вопросы