2011-02-10 1 views
2

Мне нужно выполнить синтаксический анализ и поиск информации из документов XML. XML-документ привязан к привязке данных XML, затем анализируется для определенных элементов. После того, как я выделил элементы, которые мне нужно проанализировать, я беру каждый по очереди (назовем его E_parent) и попытаюсь определить местоположение каждого нетекстового дочернего элемента (E_child) в общем XML-тексте E_parent и сделать некоторые манипуляции или другие.Delphi, MSXML: как получить XML-узел узла без пространства имен документов?

Проблема, с которой я столкнулась, заключается в том, что пространство имен XML-документа добавляется к XML-элементам дочерних элементов, когда к ним обращаются индивидуально.

Для примера, скажем, исходный документ выглядит следующим образом:

<?xml version="1.0" encoding="windows-1252"?> 
<RootNode xml:lang="en" xmlns="urn:blah:names:blahblah"> 
<E_parent>Some text <E_child>child text</E_child> more parent text</E_parent> 
</RootNode> 
</xml> 

Когда я пытаюсь получить доступ к XML-либо из элемента E_parent или E_child делать что-то вроде:

xmlParent := parentNode.XML; 

I получить:

<E_parent xmlns="urn:blah:names:blahblah">Some text <E_child>child text</E_child> more parent text</E_parent> 

То же самое, если я пытаюсь получить доступ к XML для E_child, я получаю:

<E_child xmlns="urn:blah:names:blahblah">child text</E_child> 

Это проблема, когда я затем попытаться выполнить поиск текста на родительский элемент, так как «реальный» текст не содержит, что объявление пространства имен:

Some text <E_child>child text</E_child> more parent text 

До сих пор я это связано с обнаружением/удалением нежелательных атрибутов пространства имен в строках, но оно очень неэффективно и некрасиво; o) Итак, мой вопрос заключается в том, как я могу получить XML-данные различных узлов из связанного XML-документа без пространство имен документов добавляется в теги?

=========

Благодаря Реми, это было настолько очевидно, мне просто нужно начать с пустой строки и построить его, а не начинать с внутреннего XML!

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

+3

Поиск текста внутри XML? Что вы на самом деле пытаетесь сделать здесь? –

+0

@ Leonardo: Вопрос, который я должен был задать * перед отправкой ответа.

+0

Если вы хотите зарегистрировать точный XML-код, вам не следует вообще извлекать что-либо из вашего объекта XML. Это позволит * повторно сериализовать * объект, поэтому, даже если он не включает пространства имен, он все равно может отличаться от исходного текста XML. Вместо этого вернитесь и зарегистрируйте исходный текст, который вы поместили в объект XML, в первую очередь. –

ответ

1

Используйте DOM для обработки содержимого E_parent в. Вместо этого, возвращая XML E_parent, а затем ищем тег E_child внутри него, используйте DOM, чтобы определить, какой простой текст существует перед узлом E_child (обычный текст будет иметь собственный дочерний узел), а длина этого plain-text сообщит вам точную текстовую позицию E_Child, не требуя полностью восстановить XML E_parent. E-parent будет иметь несколько дочерних узлов текстового текста в соответствующих положениях для каждого раздела непомеченного текста.

Другими словами, учитывая XML вы показали, структура DOM будет выглядеть примерно так:

RootNode 
| 
-- E_parent 
    | 
    |- "Some text " 
    | 
    |- E_child 
    | | 
    | -- "child text" 
    | 
    -- " more parent text" 
+0

Да, и это было так просто, я не думал об этом. Мне просто нужно начать с пустой строки, затем пройти через дочерние элементы, добавить их в результирующую строку, если они являются текстом, пометить их позицию (и любую другую информацию, в которой я нуждаюсь) в противном случае, а затем продолжить. Благодаря! – Bourgui

0

Используйте код, который у вас есть, а затем используйте Pos/PoxEx, чтобы найти начало и конец элемента E_Child.

var 
    cStart, cEnd: Integer; 
    ChildName, ChildText: string; 
begin 
    ... other code 
    xmlParent := parentNode.XML; 
    ChildName := 'E_Child'; 
    // Find starting position of child tag 
    cStart := Pos('<' + E_Child, xmlParent); 
    // You now have the opening < 
    cEnd := PosEx('</' + E_Child, xmlParent, cStart); 
    // You now have the final < of the child. 
    // Add the length of the child's name + the closing > 
    Inc(cEnd, Length('</' + E_Child + '>')); 
    // Grab the entire child XML 
    ChildText := System.Copy(xmlParent, cStart, cEnd - cStart); 
    // Do whatever you want with the child. For instance, 
    // remove the original text. 
    System.Delete(xmlParent, cStart, cEnd - cStart); 
    // Replace it with new text 
    System.Insert(NewChildText, xmlParent, cStart); 
end; 
+0

Я думал об этом так, но поскольку соответствующие дочерние элементы имеют несколько типов (~ 12 прямо сейчас, но это может расти), я думал, что быстрее будет цикл через ChildNodes из E_parent, проверьте, является ли это элементом (а не текстовым узлом), и только затем проверяет, имеет ли он тип, который мне интересен (и если это заменит его XML). Это должно быть быстрее, чем проверять каждый узел для каждого варианта открывающих тегов. Как я уже упоминал, я нашел обходной путь, но я надеялся на более «элегантное» решение. – Bourgui

+0

Тогда ваш вопрос не имеет смысла. Если вы планируете циклически управлять дочерними узлами E_Parent, вам не нужно беспокоиться о пространстве имен документов. Просто перейдите через E_Parent.ChildNodes вместо этого, и пространство имен не имеет значения. Я думал, что вы пытаетесь * не * итерации, но по какой-то причине работать с необработанным XML. –

+0

Надеюсь, мое редактирование сделает все более ясным: o) – Bourgui

0

В принципе, вы не можете использовать ничего, кроме анализатора XML, для анализа XML. RegEx won't work. Все, что проще, чем RegEx, тоже не будет работать.

В какой-то момент XML, который вы пытаетесь проанализировать, изменится, нарушив ваш простой код поиска/замены.

Что вам нужно сделать, это определить в терминах XML то, что нужно заменить, а не в текстовых терминах.

Вы получите определение того, какие узлы должны быть изменены/вставлены/удалены.

Затем вам нужно перевести это в код DOM Delphi.

Что-то, что может помочь большое время, - это инструмент XML (например, XML Spy, но есть еще много), которые дают вам представление дерева DOM вашего XML.

Поместите оригинальный старый XML и измените новый XML рядом друг с другом.

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

--jeroen

1

Другой подход заключается в использовании XPath для навигации по XML.

Учитывая образец XML

<?xml version="1.0" encoding="windows-1252"?> 
<RootNode xml:lang="en" xmlns="urn:blah:names:blahblah"> 
<E_parent>Some text <E_child>child text</E_child> more parent text</E_parent> 
</RootNode> 

Вы можете использовать анализатор MSXML для навигации к элементу E_child напрямую, используя немного XPath. Сначала вам нужно создать собственную копию блока MSXML2_TLB. Вы можете использовать Delphi код, который выглядит примерно так, чтобы получить доступ к узлам E_child:

uses MSXMLDOM,MSXML2_TLB; 

procedure Sample; 
var 
    doc: IXMLDOMDocument2; 
    root: IXMLDomElement; 
    nodes: IXMLDOMNodeList; 
    node: IXMLDOMNode; 
begin 

    doc := CoDOMDocument60.Create; 
    doc.async := false; 
    // Use same namespace as the default namespace here 
    doc.setProperty('SelectionNamespaces', 'xmlns:t="urn:blah:names:blahblah"'); 
    doc.setProperty('SelectionLanguage', 'XPath'); 
    doc.loadXML(XmlSource.Text); 

    root := doc.documentElement; 
    nodes := root.selectNodes('//t:E_child'); 

    // Now thee nodes contains all E_child nodes 
    // Processs them here 
    // ... 
end; 

Ключевым моментом является то, что вы используете определенный префикс для пространства имен документов по умолчанию для XPath запросов. // t: E_child - это фактическое выражение XPath, используемое для поиска элементов E_child.