Поиск в XML и получение подмножества узлов в виде XML - PullRequest
2 голосов
/ 18 июля 2010

С учетом условия поиска, как искать атрибуты узлов в XML и возвращать XML, который содержит только те узлы, которые совпадают с термином вместе со своими родителями, вплоть до корневого узла.

Вот пример ввода XML:

<root>
  <node name = "Amaths"> 
    <node name = "Bangles"/> 
  </node>
  <node name = "C">
    <node name = "Dangles">
      <node name = "E"> 
        <node name = "Fangles"/> 
      </node>
    </node>
    <node name = "Gdecimals" />
  </node>
  <node name = "Hnumbers"/> 
  <node name = "Iangles"/> 
</root>

Вывод, который я ищу для поискового запроса "angles":

<root>
  <node name = "Amaths"> 
    <node name = "Bangles"/> 
  </node>
  <node name = "C">
    <node name = "Dangles">
      <node name = "E"> 
        <node name = "Fangles"/> 
      </node>
    </node>
  </node>
  <node name = "Iangles"/> 
</root>

XPath, который я использую для поиска в xml: "// * [содержит (@ name, 'angles')]"

Я использую Nokogiri в Ruby для поиска в XML, который предоставляет мне NodeSet всех узлов, соответствующих данному термину. Я не могу понять, как создать обратно XML из этого набора узлов.

Спасибо!

РЕДАКТИРОВАТЬ: Исправлено должно было быть в примере. Спасибо, Димитр.

РЕДАКТИРОВАТЬ 2: снова исправил xml для правильного формирования.

1 Ответ

2 голосов
/ 18 июля 2010

Во-первых, обратите внимание, что представленный требуемый вывод неправильный , и у следующего элемента нет конечного тега позже в документе:

<node name = "C">

Результатом оценки выражений XPath может быть набор узлов из документа XML, но эти примечания не могут быть изменены XPath .

Это выражение XPath выбирает

узлов, которые соответствуют термину вместе с их родители полностью прослеживают корневой узел

//*[contains(@name,'angles') and not(node())]/ancestor::*

Однако узлы не изменены, и они содержат все свои дочерние элементы, что означает, что полное поддерево с корнем в Root все еще является поддеревом Root в возвращенном результате.

Если вы хотите получить новый документ (набор узлов) с структурой, отличной от исходного XML-документа, вы должны использовать другой язык, на котором размещается XPath . Существует много таких языков, таких как XSLT, XQuery и любой язык с реализацией XML DOM.

Вот XSLT-преобразование, дающее желаемый результат :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="*[not(descendant-or-self::*[contains(@name, 'angles')])]"/>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному XML-документу (исправлено, чтобы оно было правильно сформировано) :

<root>
  <node name = "Amaths">
    <node name = "Bangles"/>
  </node>
  <node name = "C">
    <node name = "Dangles">
      <node name = "E">
        <node name = "Fangles"/>
      </node>
      <node name = "Gdecimals" />
    </node>
  </node>
  <node name = "Hnumbers"/>
  <node name = "Iangles"/>
</root>

желаемый (правильный) результат получается :

<root>
   <node name="Amaths">
      <node name="Bangles"/>
   </node>
   <node name="C">
      <node name="Dangles">
         <node name="E">
            <node name="Fangles"/>
         </node>
      </node>
   </node>
   <node name="Iangles"/>
</root>
...