Как найти позицию в xml

This question is close, but it’s looking for the ordinal position. I’m looking for the actual index position in a given source string.

Better Explanation:

I have the following string

"<a>
    <b>zyx</b>
    <b>wvu</b>
    <b>tsr</b>
    <b>qpo</b>
</a>"

I’m loading that string into a .NET XmlDocument object. Carriage Returns and Line Fees may be a factor here.

Dim xmlSearchText As New XmlDocument()
xmlSearchText.LoadXml(SearchTextBox.Text)

Dim selectedNode As XmlNode = xmlSearchText.SelectSingleNode(txtSearch.Text)

The following XPath Statement could be used to find the 3rd node:

a/b[.='tsr']

However, I need it to return a string index of 23 rather than the ordinal position of 3.

Possible? Not Possible?

Community's user avatar

asked May 7, 2009 at 18:52

Joshua Hayworth's user avatar

Joshua HayworthJoshua Hayworth

7672 gold badges9 silver badges21 bronze badges

2

Does this give you what you want?

selectedNodenode = xmlSearchText.SelectSingleNode("a/b[.='tsr']");
selectedNode.ParentNode.OuterXml.IndexOf(selectedNode.OuterXml)

Won’t give you the index from the root, but it’ll give you the index from the parent node.

answered May 7, 2009 at 19:19

Crispy's user avatar

1

Using XPathDocument instead of XmlDocument will let you access the IXmlLineInfo interface with line number and column position.

XPathDocument document = new XPathDocument("file.xml");
XPathNavigator navigator = document.CreateNavigator();
XPathNavigator node = navigator.Select("a/b[.='tsr']");
IXmlLineInfo info = ((IXmlLineInfo)node);
Console.WriteLine("Found at ({0},{1})",info.LineNumber,info.LinePosition);

If you really need the character index from the string, you can deduce it by counting newlines int the string and adding the column.

answered May 7, 2009 at 20:30

Coincoin's user avatar

CoincoinCoincoin

27.7k7 gold badges54 silver badges76 bronze badges

Anyone know how to get the position of a node using XPath?

Say I have the following xml:

<a>
    <b>zyx</b>
    <b>wvu</b>
    <b>tsr</b>
    <b>qpo</b>
</a>

I can use the following xpath query to select the third <b> node (<b>tsr</b>):

a/b[.='tsr']

Which is all well and good but I want to return the ordinal position of that node, something like:

a/b[.='tsr']/position()

(but a bit more working!)

Is it even possible?

edit: Forgot to mention am using .net 2 so it’s xpath 1.0!


Update: Ended up using James Sulak’s excellent answer. For those that are interested here’s my implementation in C#:

int position = doc.SelectNodes("a/b[.='tsr']/preceding-sibling::b").Count + 1;

// Check the node actually exists
if (position > 1 || doc.SelectSingleNode("a/b[.='tsr']") != null)
{
    Console.WriteLine("Found at position = {0}", position);
}

Syscall's user avatar

Syscall

19.2k10 gold badges36 silver badges52 bronze badges

asked Oct 22, 2008 at 15:51

Wilfred Knievel's user avatar

Wilfred KnievelWilfred Knievel

3,2171 gold badge26 silver badges33 bronze badges

1

Try:

count(a/b[.='tsr']/preceding-sibling::*)+1.

Wayne's user avatar

Wayne

59.5k15 gold badges131 silver badges126 bronze badges

answered Oct 22, 2008 at 18:46

James Sulak's user avatar

James SulakJames Sulak

31.2k11 gold badges51 silver badges57 bronze badges

3

You can do this with XSLT but I’m not sure about straight XPath.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" indent="yes" 
              omit-xml-declaration="yes"/>
  <xsl:template match="a/*[text()='tsr']">
    <xsl:number value-of="position()"/>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>

answered Oct 22, 2008 at 16:39

Steven Huwig's user avatar

Steven HuwigSteven Huwig

19.8k9 gold badges55 silver badges79 bronze badges

I realize that the post is ancient.. but..

replace’ing the asterisk with the nodename would give you better results

count(a/b[.='tsr']/preceding::a)+1.

instead of

count(a/b[.='tsr']/preceding::*)+1.

answered Aug 9, 2010 at 2:32

user414661's user avatar

If you ever upgrade to XPath 2.0, note that it provides function index-of, it solves problem this way:

index-of(//b, //b[.='tsr'])

Where:

  • 1st parameter is sequence for searching
  • 2nd is what to search

answered Sep 21, 2015 at 16:14

CroWell's user avatar

CroWellCroWell

6068 silver badges15 bronze badges

3

Unlike stated previously ‘preceding-sibling’ is really the axis to use, not ‘preceding’ which does something completely different, it selects everything in the document that is before the start tag of the current node. (see http://www.w3schools.com/xpath/xpath_axes.asp)

answered Aug 4, 2010 at 20:57

Damien's user avatar

DamienDamien

2,2541 gold badge22 silver badges30 bronze badges

1

Just a note to the answer done by James Sulak.

If you want to take into consideration that the node may not exist and want to keep it purely XPATH, then try the following that will return 0 if the node does not exist.

count(a/b[.='tsr']/preceding-sibling::*)+number(boolean(a/b[.='tsr']))

answered Nov 27, 2014 at 14:35

Claus Jensen's user avatar

The problem is that the position of the node doesn’t mean much without a context.

The following code will give you the location of the node in its parent child nodes

using System;
using System.Xml;

public class XpathFinder
{
    public static void Main(string[] args)
    {
        XmlDocument xmldoc = new XmlDocument();
        xmldoc.Load(args[0]);
        foreach ( XmlNode xn in xmldoc.SelectNodes(args[1]) )
        {
            for (int i = 0; i < xn.ParentNode.ChildNodes.Count; i++)
            {
                if ( xn.ParentNode.ChildNodes[i].Equals( xn ) )
                {
                    Console.Out.WriteLine( i );
                    break;
                }
            }
        }
    }
}

answered Oct 23, 2008 at 8:20

Andrew Cox's user avatar

Andrew CoxAndrew Cox

10.6k3 gold badges33 silver badges38 bronze badges

1

I do a lot of Novell Identity Manager stuff, and XPATH in that context looks a little different.

Assume the value you are looking for is in a string variable, called TARGET, then the XPATH would be:

count(attr/value[.='$TARGET']/preceding-sibling::*)+1

Additionally it was pointed out that to save a few characters of space, the following would work as well:

count(attr/value[.='$TARGET']/preceding::*) + 1

I also posted a prettier version of this at Novell’s Cool Solutions: Using XPATH to get the position node

answered Nov 12, 2008 at 20:07

geoffc's user avatar

geoffcgeoffc

4,0107 gold badges44 silver badges50 bronze badges


DOM: Как узнать позицию в XML-файле?

От: Аноним

 
Дата:  07.03.06 08:58
Оценка:

Проблема проста: XML-документ, считанный в представление DOM, как-то обрабатывается.
Ну то есть так:

   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   Document document = builder.parse(configFile);
   ...

В некоторый момент становится ясно, что структура файла нарушена. Печатаем сообщение об ошибке.
Хочется в нём указать хотя бы строку в исходном файле, где находится ошибка.

Как это сделать — узнать строку в исходном XML?
Нагуглить не получается, в сорцах J2SE 5.0 не вижу ничего полезного…


Re: DOM: Как узнать позицию в XML-файле?

От:

dshe

 
Дата:  07.03.06 09:06
Оценка:

Здравствуйте, Аноним, Вы писали:

А>Проблема проста: XML-документ, считанный в представление DOM, как-то обрабатывается.

А>Ну то есть так:

А>

А>   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
А>   DocumentBuilder builder = factory.newDocumentBuilder();
А>   Document document = builder.parse(configFile);
А>   ...
А>



А>В некоторый момент становится ясно, что структура файла нарушена. Печатаем сообщение об ошибке.

А>Хочется в нём указать хотя бы строку в исходном файле, где находится ошибка.

А>Как это сделать — узнать строку в исходном XML?

SAXException может содержать полезную информацию, если он не содержит, значит надо сменить SAX Parser.


Дмитро


Re[2]: DOM: Как узнать позицию в XML-файле?

От: Аноним

 
Дата:  07.03.06 09:17
Оценка:

Здравствуйте, dshe, Вы писали:

D>SAXException может содержать полезную информацию, если он не содержит, значит надо сменить SAX Parser.

Дело ведь в том, что я не использую SAX. У меня уже есть модель DOM. Насколько я понимаю, пользователь не имеет контроля над подстроением DOM и, соответственно, над SAX парсерами и SAX исключениями.


Re[3]: DOM: Как узнать позицию в XML-файле?

От:

dshe

 
Дата:  07.03.06 09:26
Оценка:

Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, dshe, Вы писали:


D>>SAXException может содержать полезную информацию, если он не содержит, значит надо сменить SAX Parser.


А>Дело ведь в том, что я не использую SAX. У меня уже есть модель DOM. Насколько я понимаю, пользователь не имеет контроля над подстроением DOM и, соответственно, над SAX парсерами и SAX исключениями.

Какие тогда ты классы используешь?
javax.xml.parsers.DocumentBuilder.parse(…) методы бросают SAXException

Приведи более полный пример кода с импортами и обработкой исключений.


Дмитро


Re[3]: DOM: Как узнать позицию в XML-файле?

От:

dshe

 
Дата:  07.03.06 09:34
Оценка:

Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, dshe, Вы писали:


D>>SAXException может содержать полезную информацию, если он не содержит, значит надо сменить SAX Parser.


А>Дело ведь в том, что я не использую SAX. У меня уже есть модель DOM. Насколько я понимаю, пользователь не имеет контроля над подстроением DOM и, соответственно, над SAX парсерами и SAX исключениями.

В DOM Document’е информация об источнике не хранится. Т.е. если парсинг прошел успешно и документ сформирован, то узнать, какой тэг на какой строке в каком файле находится, в общем случае невозможно. Попробуй валидировать xml парсером (по DTD или схеме) в момент построения DOM Document’а.


Дмитро


Re[4]: DOM: Как узнать позицию в XML-файле?

От: Аноним

 
Дата:  07.03.06 09:43
Оценка:

Здравствуйте, dshe, Вы писали:

D>В DOM Document’е информация об источнике не хранится. Т.е. если парсинг прошел успешно и документ сформирован, то узнать, какой тэг на какой строке в каком файле находится, в общем случае невозможно. Попробуй валидировать xml парсером (по DTD или схеме) в момент построения DOM Document’а.

Нет, это не подходит, к сожалению… Документ уже построен, я его обхожу несколько раз и нахожу некоторые зависимости между нодами. Если зависимости нарушаются — говорю: такая вот нода — плохая (то бишь тег). Документы здоровые, однотиптных тегов много, и информация об их местонахождении в файле была бы очень полезна.

Вот шаблон, на котором у меня всё построено:


import java.io.*;
import java.util.*;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory;  
import javax.xml.parsers.ParserConfigurationException;

public class XMLTest {
    public static void main(String[] a) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(a[0]);
        NodeList nodes = document.getElementsByTagName("tag");

        if(nodes.getLength() > 1) {
            System.out.println("tag node has more tyhat one instances");
            return;
        }

        nodes = nodes.item(0).getChildNodes();

        for(int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
        
            System.out.println("Node type: '" + node.getNodeType() + "'");
            System.out.println("Node name: '" + node.getNodeName() + "'");
            System.out.println("Node value: '" + node.getNodeValue() + "'");
        }
    }
}


Re: DOM: Как узнать позицию в XML-файле?

От:

C0s

Россия

 
Дата:  07.03.06 09:54
Оценка:

4 (1)

Здравствуйте, Аноним, Вы писали:

А>В некоторый момент становится ясно, что структура файла нарушена. Печатаем сообщение об ошибке.

А>Хочется в нём указать хотя бы строку в исходном файле, где находится ошибка.

1) синтаксические проблемы далеко не всегда настолько просты, что можно показать адекватный номер строки. иногда доступен только тот номер, на котором стало понятно, что все плохо, и он может сильно отличаться от того места, где реально накосячили.
с этим практически ничего поделать нельзя — xml по задумке должен генерироваться, а не пишется от начала до конца руками, поэтому делать заточки в парсерах на глубокий анализ ошибок в общем-то их производителям не выгодно.

2) большинство остальных проблем имеет смысл попробовать решить с помощью парсера на основе XML Schema Definition, проверяющего валидность. в некоторых случаях и с номерами строк должно стать получше, и кода вам писать меньше для всех ситуаций, контроль которых покроется возможностями XSD

3) все, что не покроется XSD, т.е. совсем высокоуровнеый анализ, можно делать с использованием каких-то ключевых данных, которые в Вашем XML наверняка есть. уникальные строковые имена — или что-то подобное. тогда в сообщениях о семантических ошибках достаточно включать эту информацию, и нужный тег можно будет без труда найти


Re[5]: DOM: Как узнать позицию в XML-файле?

От:

Blazkowicz

Россия

 
Дата:  07.03.06 10:43
Оценка:

1 (1)

Здравствуйте, Аноним, Вы писали:

А>Нет, это не подходит, к сожалению… Документ уже построен, я его обхожу несколько раз и нахожу некоторые зависимости между нодами. Если зависимости нарушаются — говорю: такая вот нода — плохая (то бишь тег). Документы здоровые, однотиптных тегов много, и информация об их местонахождении в файле была бы очень полезна.

А не пробовал всю валидацию в XSD схему засунуть? И не использовать код для этого.

http://rsdn.org/File/13923/ukliam3.gif

Подождите ...

Wait...

  • Переместить
  • Удалить
  • Выделить ветку

Пока на собственное сообщение не было ответов, его можно удалить.

Имеется xml размером около 200Мб
При попытке открыть его с помощью STDU XML Editor получаю ошибку: «Illegal xml character. line: 52, position: 16420046»
Нужно понять что там за символ, и к какому объекту в выгруженных данных он относится.
Пытался открыть с помощью Notepad++ он с таким размером файла просто виснет. (виндовый блокнот тем более)
Открыл в Far Manager, 52 строку нашел быстро, а вот крутить по горизонтали до 16420046 как то не хочется.
Подскажите редактор, которым можно быстро спозиционироваться на нужный символ, и который не будет виснуть от 200 мегабайт?


  • Вопрос задан

    21 февр.

  • 52 просмотра

UPD: VSCode спокойно переварил полгигабайта — только что проверил. В строке состояния можно выбрать строку, а столбец через меню «Выделение -> Режим выбора столбца».

Illegal xml character. line: 52, position: 16420046

Судя по ошибке — этот файл очень широкий в ширину. Длина строки за 10 млн.
Действительно хрен перемотаешь.

Его можно отформатировать через xmllint. В Linux можно так сделать.

xmllint --format file.xml

Если у тебя Windows — то установи себе WSL. Полезная штука. Для таких мелких манипуляций.

Потом можно этот файл открывать через твой SDU и навигация к строке уже будет более привычной.

Пригласить эксперта


  • Показать ещё
    Загружается…

28 мая 2023, в 11:41

8000 руб./за проект

28 мая 2023, в 11:31

1500 руб./за проект

28 мая 2023, в 11:22

12000 руб./за проект

Минуточку внимания

У меня это работает, следуя этому примеру:

Generating DOM from XML preserving line numbers

Это решение следует методу, предложенному Майклом Кей. Вот как вы его используете:

// XmlTest.java

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

public class XmlTest {
    public static void main(final String[] args) throws Exception {

        String xmlString = "<foo>n"
                         + "    <bar>n"
                         + "        <moo>Hello World!</moo>n"
                         + "    </bar>n"
                         + "</foo>";

        InputStream is = new ByteArrayInputStream(xmlString.getBytes());
        Document doc = PositionalXMLReader.readXML(is);
        is.close();

        Node node = doc.getElementsByTagName("moo").item(0);

        System.out.println("Line number: " + node.getUserData("lineNumber"));
    }
}

Если вы запустите эту программу, она выйдет: «Номер строки: 3»

PositionalXMLReader — это слегка измененная версия приведенного выше примера.

// PositionalXMLReader.java

import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class PositionalXMLReader {
    final static String LINE_NUMBER_KEY_NAME = "lineNumber";

    public static Document readXML(final InputStream is) throws IOException, SAXException {
        final Document doc;
        SAXParser parser;
        try {
            final SAXParserFactory factory = SAXParserFactory.newInstance();
            parser = factory.newSAXParser();
            final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            doc = docBuilder.newDocument();
        } catch (final ParserConfigurationException e) {
            throw new RuntimeException("Can't create SAX parser / DOM builder.", e);
        }

        final Stack<Element> elementStack = new Stack<Element>();
        final StringBuilder textBuffer = new StringBuilder();
        final DefaultHandler handler = new DefaultHandler() {
            private Locator locator;

            @Override
            public void setDocumentLocator(final Locator locator) {
                this.locator = locator; // Save the locator, so that it can be used later for line tracking when traversing nodes.
            }

            @Override
            public void startElement(final String uri, final String localName, final String qName, final Attributes attributes)
                    throws SAXException {
                addTextIfNeeded();
                final Element el = doc.createElement(qName);
                for (int i = 0; i < attributes.getLength(); i++) {
                    el.setAttribute(attributes.getQName(i), attributes.getValue(i));
                }
                el.setUserData(LINE_NUMBER_KEY_NAME, String.valueOf(this.locator.getLineNumber()), null);
                elementStack.push(el);
            }

            @Override
            public void endElement(final String uri, final String localName, final String qName) {
                addTextIfNeeded();
                final Element closedEl = elementStack.pop();
                if (elementStack.isEmpty()) { // Is this the root element?
                    doc.appendChild(closedEl);
                } else {
                    final Element parentEl = elementStack.peek();
                    parentEl.appendChild(closedEl);
                }
            }

            @Override
            public void characters(final char ch[], final int start, final int length) throws SAXException {
                textBuffer.append(ch, start, length);
            }

            // Outputs text accumulated under the current node
            private void addTextIfNeeded() {
                if (textBuffer.length() > 0) {
                    final Element el = elementStack.peek();
                    final Node textNode = doc.createTextNode(textBuffer.toString());
                    el.appendChild(textNode);
                    textBuffer.delete(0, textBuffer.length());
                }
            }
        };
        parser.parse(is, handler);

        return doc;
    }
}

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Очень темный татуаж бровей как исправить
  • Как найти наименьшую неправильную дробь
  • Как найти площадь прямоугольника по двум сторонам
  • Как найти площать треугольника по 2 сторонам
  • Как найти заказчиков на отшив одежды

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии