powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Наложение (merge) DOM/XML друг на друга
12 сообщений из 12, страница 1 из 1
Наложение (merge) DOM/XML друг на друга
    #34554933
Greendrake
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как бы сделать вот такой финт ушами:

XML1:
<node1 attr1="foo" />

XML2:
<node1 attr2="bar">
<subnode />
</node1>

Нужно получить их сумму:
<node1 attr1="foo" attr2="bar">
<subnode />
</node1>

Вижу 2 пути решения задачи:
1. Манипуляции с DOM, SimpleXML и иже с ними (преобразование в массивы, их merge-ние) и т. п. (требуемый язык — PHP).
2. Универсальное решение на XSLT. Исходные XML объединяем в один:
<root>
<xml1>
<node1 attr1="foo" />
</xml1>
<xml2>
<node1 attr2="bar">
<subnode />
</node1>
</xml2>
</root>

и пишем какой-то хитровывернутый XSLT-шаблон, который это преобразует в то что требуется. Может кто-то уже решал эту задачу одним из этих, или может ещё каким путём?
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34555023
SuSa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Напишу основную идею, время будет допишу полностью.
Примерно так
Код: plaintext
1.
2.
3.
4.
5.
XML1: <!-- предположим имя документа 6a.xml -->
<node1 attr1="foo" />

XML2:<!-- предположим имя документа 6.xml , его и парсим-->
<node1 attr2="bar"> text</node1> <!--Именно текст, а не теги. Как обойтись с тегами надо вспоминать -->
xsl:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
<xsl:template match="/">
    <xsl:if test="document('6a.xml')/node()/name()=current()/node()/name()">
        <xsl:element name="{current()/node()/name()}">
            <xsl:attribute name="{current()/node()/@*/name()}" select="current()/node()/@*"/>
            <xsl:attribute name="{document('6a.xml')/node()[name()=current()/node()/name()]/@*/name()}" select="document('6a.xml')/node()[name()=current()/node()/name()]/@*"/>    
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:if>
</xsl:template>
Результат:
Код: plaintext
1.
2.
<?xml version="1.0" encoding="UTF-8"?>
<node1 attr2="bar" attr1="foo">t    </node1>
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34555123
SuSa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Замечания по своему коду.
1.Он оказался не очень универсальным. Если в исходном элементе более чем один атрибут, то прога проста загнется.
2.Чтобы вывести вложенные теги
вместо:
Код: plaintext
<xsl:value-of select="."/>
можно написать:
Код: plaintext
<xsl:copy-of select="current()/node()/descendant::*"/>
это один из вариантов.
Подожди может кто еще напишет :)
А я еще подумаю
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34555504
maXmo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Greendrake
2. Универсальное решение на XSLT. Исходные XML объединяем в один:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
<root>
    <xml1>
        <node1 attr1="foo" />
    </xml1>
    <xml2>
        <node1 attr2="bar">
            <subnode />
        </node1>
    </xml2>
</root>
и пишем какой-то хитровывернутый XSLT-шаблон, который это преобразует в то что требуется. Может кто-то уже решал эту задачу одним из этих, или может ещё каким путём?очень пространное задание
Код: plaintext
1.
2.
3.
4.
5.
6.
    <xsl:template match="/">
        <node1>
            <xsl:copy-of select="*/node1/@*"/>
            <xsl:copy-of select="*/node1/*"/>
        </node1>
    </xsl:template>
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34555506
maXmo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
    <xsl:template match="/root">
        <node1>
            <xsl:copy-of select="*/node1/@*"/>
            <xsl:copy-of select="*/node1/*"/>
        </node1>
    </xsl:template>
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34555548
Greendrake
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Имелось ввиду универсальное решение, не привязанное к конкретному XML, node1 и т. п.
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34555916
maXmo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
насколько универсальное и насколько не привязанное? Поподробнее.
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34556074
Greendrake
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maXmoнасколько универсальное и насколько не привязанное? Поподробнее.
Ну то есть чтобы можно было взять два любых XML-файла и смержить их. Если у них вообще нет ничего общего, то должен получиться файл-склейка из двух (ну, может в котором их содержимое объединено под одним корневым контейнером для валидности). Если у них есть одноимённые ноды, то они мержатся, как в примере выше.
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34557105
TiG
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Greendrake maXmoнасколько универсальное и насколько не привязанное? Поподробнее.
Ну то есть чтобы можно было взять два любых XML-файла и смержить их. Если у них вообще нет ничего общего, то должен получиться файл-склейка из двух (ну, может в котором их содержимое объединено под одним корневым контейнером для валидности). Если у них есть одноимённые ноды, то они мержатся, как в примере выше.

FULL OUTER JOIN двух произвольных xml-ей ? ;-))
Тогда наверное брать за основу то что писал SuSa только есессно с полным обходом + он забыл про содержимое 2го которое никак не пересекается с первым, т.е. "Обходим рекурсивно первое дерево, полностью копируем его в результат + на каждом уровне добавляем то что есть во втором, но нет в первом".
Кстати возможно вам проще это будет написать на (в вашем случае) PHP, манипулируя двумя DOM-ами. К тому же и понятнее, если не сталкивались раньше с XSLT ;-)

ЗЫ простота дальнейшего сопровождения и развития созданного продукта - великое дело :)
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34571814
Greendrake
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Решил всё-же идти по пути XSLT. В принципе получилось, но с некоторыми нюансами:

1. Входящие XML не равноценны. Один используется как master, второй как slave. Принцип действия таков, что обходятся все ноды мастера, и если у слэйва есть соответствующая нода, и в ней есть дополнительные атрибуты — они добавляются в результирующее дерево. При этом, если нода слэйва содержит потомков, которых у мастера нет, они копируются целиком.
2. Шаблон хорошо работает только для исходных XML без повторяющихся на одном и том же уровне нод. Если ноды на одном уровне будут повторяться, то результат неудовлетворителен. Были попытки решить эту проблему путём запоминания ID нод (функция generate-id()), но пока они не увенчались успехом.

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

<xsl:template match="root">
<xsl:variable name="n1" select="document('m1.xml')" />
<xsl:variable name="n2" select="document('m2.xml')" />
<root>
<xsl:for-each select="$n1/*">
<xsl:variable name="n" select="local-name()" />
<xsl:apply-templates select=".">
<xsl:with-param name="n2" select="$n2/*[local-name()=$n]" />
</xsl:apply-templates>
</xsl:for-each>
</root>
</xsl:template>

<xsl:template match="*|@*">
<xsl:param name="n2" />
<xsl:variable name="n1" select="." />
<xsl:copy select=".">
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="$n2/@*" />
<xsl:for-each select="*">
<xsl:variable name="n" select="local-name()" />
<xsl:choose>
<xsl:when test="$n2 and $n2/*[local-name()=$n]">
<xsl:apply-templates select=".">
<xsl:with-param name="n2" select="$n2/*[local-name()=$n]" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:for-each select="$n2/*">
<xsl:variable name="n" select="local-name()" />
<xsl:if test="not($n1/*[local-name()=$n])">
<xsl:copy-of select="." />
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34573375
maXmo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чувствую, можно изратиться, но это будет нетривиально
...
Рейтинг: 0 / 0
Наложение (merge) DOM/XML друг на друга
    #34573427
maXmo
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот, извратился, вроде пашет :)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
<xsl:template match="root">
 <xsl:variable name="doc1" select="document('m1.xml')" />
 <xsl:variable name="doc2" select="document('m2.xml')" />
 <root>
  <xsl:call-template name="merge">
   <xsl:with-param name="nodes" select="$doc1/*|$doc2/*"/>
  </xsl:call-template>
 </root>
</xsl:template>

<xsl:template name="merge">
 <xsl:param name="nodes"/>
 <xsl:for-each select="$nodes">
  <xsl:variable name="curname" select="local-name()"/>
  <xsl:variable name="clones" select="$nodes[local-name()=$curname]"/>
  <xsl:if test="generate-id(.)=generate-id($clones[1])">
   <xsl:copy>
    <xsl:copy-of select="$clones/@*"/>
    <xsl:call-template name="merge">
     <xsl:with-param name="nodes" select="$clones/*"/>
    </xsl:call-template>
   </xsl:copy>
  </xsl:if>
 </xsl:for-each>
</xsl:template>
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Наложение (merge) DOM/XML друг на друга
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]