отсеивание лишних узлов

Alexandre

PHPПенсионер
отсеивание лишних узлов

Есть данные на сайте, представленные в ввиде xml определенной структуры

Нужно написать XSLT преобразование, которое копировалобы данный xml за исключнением определенных веток.
Пример:
PHP:
 <root>
<contents>
  <content>
      <item id=11>
      <item id=12>
      <item id=13>
  </content>
      <item id=21>
      <item id=22>
      <item id=23>
  <content>
  </content>
</root>
на выходе получить все тоже но без : <item id=21> и <item id=12>

-~{}~ 10.09.04 19:06:

еще такое предложение,
а что если некопируемые узлы должны быть представленны в отдельных тегах шаблона, например:
PHP:
<filter>
   <id>12<id>
   <id>21<id>
   <id>35<id>
</filter>
 

cray

Guest
Кстати, item у тебя должен быть внутри content? или не обязательно? Вопщем есть такая идея... Случай для обязательного:
Исходный XML
PHP:
<root>

	<contents>
		<content>
			<item id="11" />
			<item id="12" />
			<item id="13" />
		</content>
		<content>
			<item id="21" />
			<item id="22" />
			<item id="23" />
		</content>
	</contents>

	<filter>
		<item id="12" />
		<item id="21" />
		<item id="23" />
	</filter>

</root>
XSLT:
PHP:
<xsl:stylesheet
	 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	 version="1.0">

<xsl:strip-space elements="*" />
<xsl:output indent="yes" method="xml" />

<xsl:template match="/">
	<root>
		<contents>
			<xsl:apply-templates select="/root/contents/content" />
		</contents>
	</root>
</xsl:template>

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

<xsl:template match="item">
	<xsl:if test="тут условие">
		<item id="{@id}" />
	</xsl:if>
</xsl:template>

</xsl:stylesheet>
Вместо "тут условие" нужно выражение, которое ищет количество совпадений идентификатора текущего item с item в фильтре. Если в фильтре такого нету, то его нужно вывести. По такому принципу и фильтровать....

Насчет выражения...
Я думал, что-то вроде этого, но не работает
count(/root/filter/item[@id = ./@id]) = 0
Где я ошибся? поправьте...
 

chameleon

Новичок
юзай ключи уж тогда:
PHP:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
	<xsl:key name="trans" match="item" use="count(/root/contents/content/item[generate-id(current()) != generate-id() and substring(current()/@id,2,1) = substring(@id,1,1) and substring(current()/@id,1,1) = substring(@id,2,1)])"/>
	<xsl:template match="/">
	<root>
		<contents>
			<xsl:apply-templates />
		</contents>
		<filter>
			<xsl:apply-templates select="key('trans',1)"/>
		</filter>
	</root>
	</xsl:template>
	<xsl:template match="content">
		<xsl:copy>
			<xsl:apply-templates select="key('trans',0)[generate-id(..) = generate-id(current())]"/>			
		</xsl:copy>
	</xsl:template>
	<xsl:template match="item">
		<xsl:copy-of select="."/>
	</xsl:template>
</xsl:stylesheet>
 

jian

Guest
xml:
Код:
<root> 
    <contents> 
        <content> 
            <item id="11" /> 
            <item id="12" /> 
            <item id="13" /> 
        </content> 
        <content> 
            <item id="21" /> 
            <item id="22" /> 
            <item id="23" /> 
        </content> 
    </contents> 
    <filter> 
        <item id="12" /> 
        <item id="21" /> 
        <item id="23" /> 
    </filter> 
</root>
xsl:
Код:
<xsl:stylesheet 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     version="1.0"> 

<xsl:strip-space elements="*" /> 
<xsl:output indent="yes" method="xml" /> 

<xsl:template match="/"> 
    <root> 
        <contents> 
            <xsl:apply-templates select="/root/contents/content" /> 
        </contents> 
    </root> 
</xsl:template> 

<xsl:template match="content"> 
    <content> 
        <xsl:apply-templates select="item/@id" /> 
    </content> 
</xsl:template> 

<xsl:template match="@id" > 
    <xsl:if test="not(../../../../filter/item/@id[.=current()])"> 
        <item id="{.}" /> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet>
 

chameleon

Новичок
jian
либо я, либо ты (но кто-то точно) не понял задачу ;)..
как я понял, в исходном документе нету информации о некопируемых узлах
 

cray

Guest
Спасибо jian
юзнул для текущего узла current(), так работает и мой вариант:
PHP:
<xsl:if test="count(/root/filter/item[@id = current()/@id]) = 0">
 

cray

Guest
Хотя соглашусь, что немного не в ту степь меня занесло :)
Нет смысла держать данные и фильтр на них в одном файле...
 

jian

Guest
jian

xml
Код:
<?xml version="1.0"?>
<root> 
    <contents> 
        <content> 
            <item id="11" /> 
            <item id="12" /> 
            <item id="13" /> 
        </content> 
        <content> 
            <item id="21" /> 
            <item id="22" /> 
            <item id="23" /> 
        </content> 
    </contents> 
</root>
xsl
Код:
<?xml version="1.0"?>
<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0"> 
<xsl:strip-space elements="*" /> 
<xsl:output indent="yes" method="xml" /> 

<xsl:variable name="exclude">
 <item id="12" /> 
 <item id="21" /> 
 <item id="23" /> 
</xsl:variable>

<xsl:template match="/"> 
    <root> 
        <contents> 
            <xsl:apply-templates select="/root/contents/content" /> 
        </contents> 
    </root> 
</xsl:template> 

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

<xsl:template match="item"> 
    <xsl:if test="not(document('')/*/xsl:variable/item[@id = current()/@id])"> 
        <item id="{@id}" /> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet>
resultat
Код:
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <contents>
    <content>
      <item id="11"/>
      <item id="13"/>
    </content>
    <content>
      <item id="22"/>
    </content>
  </contents>
</root>
 

jian

Guest
rulnyi eto chto? tipa zanuda?

no est processory kotorye mogut vmesto
Код:
    <xsl:if test="not(document('')/*/xsl:variable/item[@id = current()/@id])"> 
        <item id="{@id}" /> 
    </xsl:if>
sdelat to je samoe othodya ot peremennoi, kak to:
Код:
    <xsl:if test="not($exclude/tem[@id = current()/@id])"> 
        <item id="{@id}" /> 
    </xsl:if>
kajetsa xalan kotoryi ya ispolzuyu ne mojet/mog eto delat :(
 

Alexandre

PHPПенсионер
Кстати, item у тебя должен быть внутри content? или не обязательно? Вопщем есть такая идея... Случай для обязательного:
Исходный XML
cray - я тут подумал на выходных, и пришел к выводу (тогда я твой пост еще не читал), что такой вариант, как у тебя - подойдет - иначе не обойтись.
Призгаюсь честно, другие посты я пока не смотрел... Но сейчас изучу все варианты :)

-~{}~ 13.09.04 10:16:

либо я, либо ты (но кто-то точно) не понял задачу ..
как я понял, в исходном документе нету информации о некопируемых узлах
В принципе в исходном документе нет информации о тех узлах, которые надо отсеивать.

НО Шаблон должен быть таким, чтоб там жестко не прописывались условия отсеивания узлов. Т.е. условия отсеивания должныы быть либо во включаемом в шаблон файле.

Как вариант - возможно, этот файл включать в исходный xml.

-~{}~ 13.09.04 10:57:

jian
Код:
<xsl:variable name="exclude">
 <item id="12" /> 
 <item id="21" /> 
 <item id="23" /> 
</xsl:variable>
отличное решение !!!! - сейчас проверю на работоспособность.

Притом это можно формировать в отдельном шаблоне!

-~{}~ 13.09.04 11:24:

Код:
<xsl:template match="/"> 
    <root> 
        <contents> 
            <xsl:apply-templates select="/root/contents/content" /> 
        </contents> 
    </root> 
</xsl:template>
А можно использовать как-то вариант с </xsl:copy> а то в реальном xml источнике куча аттрибутов да и вложенность покруче.
 

chameleon

Новичок
<xsl:variable name="exclude"> <item id="12" /> <item id="21" /> <item id="23" /> </xsl:variable>
ужасное, негибкое решение :)...
чего ж вы ключи-то невзлюбили?
а ну-ка мне по такой схеме вычлените все элементы, которые в id имеют цифирь "3", например? либо все item'ы у которых (5 < @id < 12)
хотя, конечно, если условий для отсеивания узлов не много, то нормальное решение. С другой стороны почему их не отсеивать на этапе формирования xml документа раз они все поголовно известны? Только если этот документ - внешняя сущность?

-~{}~ 13.09.04 13:01:

А можно использовать как-то вариант с </xsl:copy>
для этого используй identity transformation.
 

jian

Guest
а ну-ка мне по такой схеме вычлените все элементы, которые в id имеют цифирь "3", например? либо все item'ы у которых (5 < @id < 12)
1)<xsl:if test="not(contains(@id,'3'))"/>
2)<xsl:if test="not(@id >5 and 12 > @id)"/>

PS not tested :)
 

Alexandre

PHPПенсионер
Ребята - не ссортесь, не надо вычленять итемы, у которых (5 < @id < 12)
 
Сверху