Гость
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Выдернуть данные по неполному пути / 7 сообщений из 7, страница 1 из 1
03.09.2019, 15:02
    #39856688
zingerion
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
Есть следующая структура xml(расписал один offer, остальные типовые)..задача стоит в том, чтобы я через командную строку Xpath-ом указывал, какой параметр мне нужно выдернуть относительно offer. То есть, это должно выглядеть так:
msxsl.exe Исходник.xml Стили.xsl -o Результат.csv SecondColumn=param[2]
или
msxsl.exe Исходник.xml Стили.xsl -o Результат.csv SecondColumn=price/Cat
<shop>
<offers>
<offer id="1" available="true">
<url> https://...</url>
<price>
<Cat>1</Cat>
<Cat>2</Cat>
</price>
<currencyId>RUR</currencyId>
<categoryId>1481</categoryId>
<picture>SomeURL.jpg</picture>
<name>Product</name>
<model>GJSER-1</model>
<vendor>Roomaif</vendor>
<description>Мягкие кожанные сандали<description>
<param>229</param>
<param>332</param>
<param name="Размер">26</param>
<barcode>4690507031995</barcode>
<offer>
.....
</offer>
<offer>
.....
</offer>
<offers>
<shop>


Мой xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl=" http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user=" http://www.contoso.com">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:param name="SecondColumn" select="SecondColumn"/>
<xsl:template match="offer">
<xsl:for-each select="msxsl:node-set($SecondColumn)">
<xsl:value-of select="." />
</xsl:for-each>
</xsl:template>

<xsl:template match="/">
<xsl:apply-templates select="yml_catalog/shop/offers/offer">
<xsl:with-param name="SecondColumn" />
</xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

На выходе должен получиться csv файл
Плиз хэлп, не вижу вообще никакого решения, а в XSLT новичок
...
Рейтинг: 0 / 0
04.09.2019, 13:46
    #39857164
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
Принципиальная ошибка
zingerion
Код: xml
1.
<xsl:for-each select="msxsl:node-set($SecondColumn)">

$SecondColumn у вас строка и в набор узлов она не конвертируется. Чтобы из нее получить набор узлов нужно ее вручную распарсить и самому выполнить все XPath запросы.

Вторая ошибка
zingerion
Код: xml
1.
<xsl:output omit-xml-declaration="yes" indent="yes"/>

если вам на выходе нужен csv, то сообщите об этом процессору
Код: xml
1.
<xsl:output encoding="UTF-8" method="text"/>



Третья ошибка. Вот эта строка
zingerion
Код: xml
1.
<xsl:param name="SecondColumn" select="SecondColumn"/>

обозначает "Объявить параметр SecondColumn. А если его значение не было передано снаружи, то присвоить ему значение узла SecondColumn в текущем контексте. Такого узла у вас нет в принципе.

В итоге получилось вот так
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"  
  xmlns:user="http://www.contoso.com">
  
  <xsl:output encoding="UTF-8" method="text"/>
  
  <xsl:param name="SecondColumn"/>
  
  <xsl:template match="/">
    <xsl:apply-templates select="/shop/offers/offer"/>
  </xsl:template>
  
  <xsl:template match="offer">
    <xsl:apply-templates select="." mode="getNode">
      <xsl:with-param name="name" select="$SecondColumn"/>
    </xsl:apply-templates>
    <xsl:text>;
</xsl:text>
  </xsl:template>
  
  <xsl:template match="*" mode="getNode">
    <xsl:param name="name"/>
    <xsl:variable name="curName" select="substring-before($name, '/')"/>
    <xsl:choose>
      <xsl:when test="$curName != ''">
        <xsl:apply-templates select="*[local-name() = $curName]" mode="getNode">
          <xsl:with-param name="name" select="substring-after($name, '/')"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="*[local-name() = $name]" mode="showNode"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template match="*" mode="showNode">
    <xsl:if test="position() &gt; 1">
      <xsl:text>,</xsl:text>
    </xsl:if>
    <xsl:value-of select="."/>
  </xsl:template>
</xsl:stylesheet>

...
Рейтинг: 0 / 0
04.09.2019, 15:18
    #39857250
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
Еще вариант решения, т.к. все равно используется MSXML написать на JS функцию, которая вернет набор узлов по указанному XPath

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"  
  xmlns:script="http://www.contoso.com/script"
  xmlns:user="http://www.contoso.com">
  
  <xsl:output encoding="UTF-8" method="text"/>
  
  <xsl:param name="SecondColumn"/>
  
  <xsl:template match="/">
    <xsl:apply-templates select="/shop/offers/offer"/>
  </xsl:template>
  
  <xsl:template match="offer">
    <xsl:apply-templates select="script:getNode(., $SecondColumn)" mode="showNode"/>
    <xsl:text>;
</xsl:text>
  </xsl:template>
  
  <msxsl:script language="JavaScript" implements-prefix="script">
    function getNode(parent, path) {
      return parent.item(0).selectNodes(path);
    }
  </msxsl:script>
  
  <xsl:template match="*" mode="showNode">
    <xsl:if test="position() &gt; 1">
      <xsl:text>,</xsl:text>
    </xsl:if>
    <xsl:value-of select="."/>
  </xsl:template>
</xsl:stylesheet>

тогда можно обойтись без ручного парсинга
...
Рейтинг: 0 / 0
04.09.2019, 18:28
    #39857434
zingerion
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
_Vasilisk_,

Спасибо за ответ! $SecondColumn является строкой т к является глобальным параметром? Или из-за того, что передается в коммандной строке?
Я так понимаю, для подобного: param[2] нужно прописать отдельный template со своим mode?
...
Рейтинг: 0 / 0
05.09.2019, 14:02
    #39857915
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
zingerionИли из-за того, что передается в коммандной строке?Из-за этого. Из программы можно передать любой VARIANT
zingerionЯ так понимаю, для подобного: param[2] нужно прописать отдельный template со своим mode?Нет. Нужно дополнить парсинг в_Vasilisk_
Код: xml
1.
<xsl:template match="*" mode="getNode">



JS функция не подошла?
...
Рейтинг: 0 / 0
05.09.2019, 16:53
    #39858051
zingerion
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
_Vasilisk_, нужно на чистом xslt, хотя решение на js работает
Воплотил замысел как-то так(убрал запяты, т к нужны "|", их я перенес в offer, т к помимо всего прочего нужно вывести offer id)
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"  
  xmlns:user="http://www.contoso.com">
  <xsl:output encoding="UTF-8" method="text"/>
  <xsl:param name="SecondColumn"/>
  
  <xsl:template match="/">
    <xsl:apply-templates select="yml_catalog/shop/offers/offer"/>
  </xsl:template>
  
  <xsl:template match="offer">
	<xsl:value-of select="@id" />
     <xsl:text>|</xsl:text>
    <xsl:apply-templates select="." mode="getNode">
      <xsl:with-param name="name" select="$SecondColumn"/>
    </xsl:apply-templates>
    <xsl:text>
</xsl:text>
  </xsl:template>
  
  <xsl:template match="*" mode="getNode">
    <xsl:param name="name"/>
    <xsl:variable name="curName" select="substring-before($name, '/')"/>
    <xsl:choose>
	       <xsl:when test="$curName != ''">
             <xsl:apply-templates select="*[local-name() = $curName]" mode="getNode">
               <xsl:with-param name="name" select="substring-after($name, '/')"/>
             </xsl:apply-templates>
           </xsl:when>
	       <xsl:otherwise>
	         <xsl:choose>
            <xsl:when test="substring-after($name, '[') != ''">
			   <xsl:variable name="number" select="substring-before($name,'[')" />
               <xsl:variable name="CurNumbName" select="number(substring-before(substring-after($name, '['), ']'))"/>
			   <xsl:apply-templates select="*[local-name() = $number]" mode="showNode">
			      <xsl:with-param name="ElemPosit" select="$CurNumbName" />
			   </xsl:apply-templates>
		    </xsl:when>
		   <xsl:otherwise>
		       <xsl:apply-templates select="*[local-name() = $name]" mode="showNode"/>
           </xsl:otherwise>
	    </xsl:choose>
	  </xsl:otherwise>
    </xsl:choose>
  </xsl:template> 
  
  <xsl:template match="*" mode="showNode">
    <xsl:param name="ElemPosit" /> 
	<xsl:choose>
	   <xsl:when test="$ElemPosit != '' ">
	     <xsl:if test="position()=$ElemPosit">
    	   <xsl:value-of select="." />
	     </xsl:if>
	   </xsl:when>
       <xsl:otherwise>
	      <xsl:value-of select="." /> 
	   </xsl:otherwise>
	</xsl:choose>
  </xsl:template>
</xsl:stylesheet>
...
Рейтинг: 0 / 0
05.09.2019, 18:42
    #39858115
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Выдернуть данные по неполному пути
Вот это
zingerion
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<xsl:choose>
  <xsl:when test="substring-after($name, '[') != ''">
    <xsl:variable name="number" select="substring-before($name,'[')" />
    <xsl:variable name="CurNumbName" select="number(substring-before(substring-after($name, '['), ']'))"/>
    <xsl:apply-templates select="*[local-name() = $number]" mode="showNode">
      <xsl:with-param name="ElemPosit" select="$CurNumbName" />
    </xsl:apply-templates>
  </xsl:when>
  <xsl:otherwise>
    <xsl:apply-templates select="*[local-name() = $name]" mode="showNode"/>
  </xsl:otherwise>
</xsl:choose>

делается так
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<xsl:choose>
  <xsl:when test="substring-after($name, '[') != ''">
    <xsl:variable name="number" select="substring-before($name,'[')" />
    <xsl:variable name="CurNumbName" select="number(substring-before(substring-after($name, '['), ']'))"/>
    <xsl:apply-templates select="*[local-name() = $number] and position() = $CurNumbName" mode="showNode"/>
  </xsl:when>
  <xsl:otherwise>
    <xsl:apply-templates select="*[local-name() = $name]" mode="showNode"/>
  </xsl:otherwise>
</xsl:choose>
...
Рейтинг: 0 / 0
Форумы / XML, XSL, XPath, XQuery [игнор отключен] [закрыт для гостей] / Выдернуть данные по неполному пути / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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