2013-10-14 5 views
0

Привет всем Я использую XPATH с XML.SelectNodes() для извлечения данных купола из файла XML, я хочу, чтобы эти данные были в определенном порядке, XML-файл выглядит так:Как добавлять узлы с помощью XPATH

<?xml version='1.0' encoding='UTF-8'?> 
    <ConvenioAladi> 
     <Operaciones> 
     <Operacion Prioridad='Alta' /> 
     <Operacion Prioridad='Media' /> 
     <Operacion Prioridad='Alta' /> 
     <Operacion Prioridad='Baja' /> 
     <Operacion Prioridad='Baja' /> 
     <Operacion Prioridad='Media' /> 
     </Operaciones> 
    </ConvenioAladi> 

И хотим получить XML так:

<?xml version='1.0' encoding='UTF-8'?> 
    <ConvenioAladi> 
     <Operaciones> 
     <Operacion Prioridad='Alta' /> 
     <Operacion Prioridad='Alta' /> 
     <Operacion Prioridad='Media' /> 
     <Operacion Prioridad='Media' /> 
     <Operacion Prioridad='Baja' /> 
     <Operacion Prioridad='Baja' /> 
     </Operaciones> 
    </ConvenioAladi> 

я способен получить один из Prioridad атрибутов в любой момент, давая XPATH:

«/ ConvenioA Ladi/Operaciones/Operacion [@ Prioridad = 'Альта'] ',

но если я попробовать что-то вроде этого: '/ ConvenioAladi/Operaciones/Operacion [@ Prioridad =' Альта' или @ Prioridad = 'Медиа 'или @ Prioridad =' Baja ']'

или: '/ ConvenioAladi/Operaciones/Operacion [@ Prioridad =' Альта '] |/ConvenioAladi/Operaciones/Operacion [@ Prioridad = 'Media'] |/ConvenioAladi/Operaciones/Operacion [@ Prioridad = 'Baja'] '

Я всегда получаю исходный XML обратно, есть ли в любом случае достижение того, о чем я упоминал раньше ?. Спасибо

+0

Почему бы не искать следующего брата с тем же значением атрибута и большей позицией? –

+0

Похоже, вы используете XPath 1. Там это невозможно. Он возвращает только набор узлов, а не последовательность. – BeniBela

+0

Ignacio Vazquez-Abrams. Как я могу это сделать, не могли бы вы привести пример? –

ответ

2

XPath в версии вы используете совпадающие узлы в порядке, которые вы не можете изменить.

Есть несколько способов его достижения:

XSLT

Один простой способ выполнить XSL Transform

После того, как вы узнаете, XSLT, становится очень легко сделать такого рода вещи. Такие, как:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 
    <xsl:template match="Operaciones"> 
     <xsl:copy> 
      <xsl:apply-templates select="Operacion"> 
       <xsl:sort select="index-of(('Alta','Media','Baja'), @Prioridad)"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

И тогда вы можете запросить все ваши Operaciones легко. Если вы выполняете маршрут XSLT, это означает, что вы можете обновить свои запросы, не перекомпилируя свое программное обеспечение. Это, вероятно, решение, которое вы хотите использовать.

Обновление: Матиас отметил, что мы не ищем алфавитный вид. Я буду держать решения ниже для справки, но теперь я бы посоветовал пойти на правильное решение XSLT выше.

XPathDocument

Второй путь более programatic, которая использует собственные функции Microsoft:

Предполагая doc является XmlDocument, вы можете сделать следующее, чтобы превратить его в XPathDocument:

XPathDocument xpathDoc = new XPathDocument(new XmlNodeReader(doc)); 

Как только вы сделаете это, вы можете запустить следующий запрос:

XPathNavigator nav = xpathDoc.CreateNavigator(); 
XPathExpression expression = XPathExpression.Compile(@"//Operacion"); 
expression.AddSort(@"@Prioridad", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Text); 
XPathNodeIterator iterator = nav.Select(expression); 
foreach (XPathNavigator operation in iterator) { 
    Console.WriteLine("Found priority '{0}'",operation.GetAttribute("Prioridad","")); 
} 

Linq

Третий способ, с помощью Linq (вы можете проверить синтаксис здесь):

XDocument xDoc = XDocument.Load(new XmlNodeReader(doc)); 
var operations = xDoc.Descendants("Operacion").OrderBy(s=>(string)s.Attribute("Prioridad")); 
foreach(var operation in operations) { 
    Console.WriteLine("hey -> {0}", operation); 
} 

Я предлагаю вам сделать это с помощью Linq, но если вы преобразования данных, а затем пойти на XSLT каждый раз.

+1

Я знаю, что это старый ответ, но ваш XSLT-код не был виден до сих пор, и это не совсем правильно. Стандартная сортировка является алфавитной, что в данном случае не является полезным. Вам придется «применять шаблоны» отдельно: http://xsltransform.net/nc4NzQD. –

+0

Спасибо @ MathiasMüller за то, что вы указали эти проблемы, очень цените! Я обновил XSLT более идиоматическим способом - все еще использую один вид. –

+1

плюс 1, но имейте в виду, что это будет работать только в XSLT 2.0, так как 'index-of()' является функцией 2.0: http://xsltransform.net/pPqsHTF. –

0

Как обсуждалось ранее, здесь есть несколько вариантов. Ради конкретности, вот (1,0) решения полной XSLT, которая до сих пор лишь намечается:

<?xml version='1.0' encoding='UTF-8'?> 

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="*"> 
    <xsl:variable name="n" select="name (.)"/> 
    <xsl:element name="{$n}"> 
     <xsl:for-each select="@*"> 
     <xsl:copy-of select="."/> 
     </xsl:for-each> 
     <xsl:apply-templates select="*"/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="/"> 
    <xsl:apply-templates select="ConvenioAladi"/> 
    </xsl:template> 

    <xsl:template match="Operaciones"> 
    <xsl:apply-templates select="Operacion[@Prioridad = &quot;Alta&quot;]"/> 
    <xsl:apply-templates select="Operacion[@Prioridad = &quot;Media&quot;]"/> 
    <xsl:apply-templates select="Operacion[@Prioridad = &quot;Baja&quot;]"/> 
    </xsl:template> 
</xsl:stylesheet> 

Вы можете применить эту таблицу стилей к вашему XML и сортируют Operacion узлов в порядке Alta, Media, Baja. Это происходит довольно наивно: он просто ищет любой Operacion со значением Alta для атрибута Prioridad и (по существу) копирует его на выход. Затем Media, затем Baja. Он будет работать, даже если нет узлов Operacion со значением Baja для их атрибута Prioridad (и аналогичным образом для двух других значений). В таблице стилей подразумевается, что эти три являются единственными возможными значениями для атрибута Prioridad (если есть такие узлы, они молча игнорируются), поэтому, если у вас есть Operacion узлы, которые могут иметь другие значения для своего атрибута Prioridad, таблица стилей необходимо будет скорректировать.

+0

Пожалуйста, прекратите публикацию плохих ответов XSLT. Ваш код работает, но он загружен ненужными конструкциями - элементы вывода могут быть _copied_ на выходе, не нужно генерировать новые элементы. Нет необходимости «для каждого» над списком известных атрибутов из ввода. Не нужно избегать цитат в XSLT, если вы используете их в качестве фактических котировок. –

+0

Тем не менее, код XSLT (невидимый до недавнего времени) в принятом ответе на этот вопрос неправильный - стандартный сорт алфавитный, что бесполезно в этом случае. Таким образом, каждый мог бы извлечь выгоду из полезного ответа XSLT в соответствии с http://xsltransform.net/nc4NzQD. –

Смежные вопросы