2016-02-17 1 views
0

У меня есть таблица стилей XSLT, которая преобразует текстовую нотацию в SVG. Он работает нормально, но обрабатывать символ можно только одним элементом. Это работает, например:Как обрабатывать последовательность с одним или несколькими элементами

GRAPHREP 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:50pt ry:50pt 

Когда я хочу, чтобы преобразовать символ с более чем одним пунктов, как это,

GRAPHREP 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:50pt ry:50pt 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:30pt ry:30pt 

Я получаю эту ошибку: XPTY0004: последовательность более одного элемента не разрешен как первый аргумент local-name(). Как можно обрабатывать один или несколько элементов? Я добавляю таблицу стилей в конце сообщения. Это, вероятно, мой последний вопрос для этой темы. Большое вам спасибо за вашу помощь!

<?xml version="1.0" encoding="UTF-8"?> 
<!-- Ansatz mit Hilfe von 
http://stackoverflow.com/questions/34682331/xslt-2-0-transform-notation-in-plain-text-to-svg --> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:local="local" 
    exclude-result-prefixes="xs" 
    version="2.0" 
    xmlns:svg="http://www.w3.org/2000/svg"> 
    <xsl:output indent="yes"/> 

<xsl:variable name="drawing-text"> 
GRAPHREP 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:50pt ry:50pt 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:30pt ry:30pt 

</xsl:variable> 
<!-- 
<xsl:param name="drawing-text" /> 
    --> 
    <!--matches sequences of UPPER-CASE letters --> 
    <xsl:variable name="label-pattern" select="'[A-Z]+'"/> 
    <!--matches the "attributes" in the line i.e. w:2pt, 
     has two capture groups (1) => attribute name, (2) => attribute value --> 
    <xsl:variable name="attribute-pattern" select="'\s?(\S+):(\S+)'"/> 
    <!--matches a line of data for the drawing text, 
     has two capture groups (1) => label, (2) attribute data--> 
    <xsl:variable name="line-pattern" select="concat('(', $label-pattern, ')\s(.*)\n?')"/> 
    <!-- Text in quotes holen--> 
    <xsl:variable name="text-pattern" select="'&quot;(.*?)&quot;'"/> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/" name="main"> 
     <svg width="640" height="480"> 
      <g> 
       <!-- Find the text patterns indicating the shape --> 
       <!--Replaced unparsed-text() with local variable for testing     
       select="unparsed-text('drawing.txt')" --> 
       <xsl:analyze-string select="$drawing-text" 
        regex="{concat('(', $label-pattern, ')\n((', $line-pattern, ')+)\n?')}"> 
        <xsl:matching-substring> 
         <!--Convert text to XML --> 
         <xsl:variable name="drawing-markup" as="element()"> 
          <!--Create an element for this group, using first matched pattern as the element name 
           (i.e. GRAPHREP => <GRAPHREP>) --> 
          <xsl:element name="{regex-group(1)}"> 
           <!--split the second matched group for this shape into lines by breaking on newline--> 
           <xsl:variable name="lines" select="tokenize(regex-group(2), '\n')"/> 
           <xsl:for-each select="$lines"> 
            <!--for each line, run through this process to create an element with attributes 
             (e.g. FILL color:$frf7f00 => <FILL color=""/> 
            --> 
            <xsl:analyze-string select="." regex="{$line-pattern}"> 
             <xsl:matching-substring> 
              <!--create an element using the UPPER-CASE label starting the line --> 
              <xsl:element name="{regex-group(1)}"> 
               <!-- capture each of the attributes --> 
               <xsl:analyze-string select="regex-group(2)" regex="\s?(\S+):(\S+)"> 
                <xsl:matching-substring> 
                <!--convert foo:bar into attribute foo="bar", 
                  translate $ => # 
                  and remove the letters 'p' and 't' by translating into nothing"--> 
                <xsl:attribute name="{regex-group(1)}" select="translate(regex-group(2), '$pt', '#')"/> 
                </xsl:matching-substring> 
                <xsl:non-matching-substring/> 
               </xsl:analyze-string> 
              </xsl:element> 
             </xsl:matching-substring> 
             <xsl:non-matching-substring/> 
            </xsl:analyze-string> 
           </xsl:for-each> 
          </xsl:element> 
         </xsl:variable> 
         <!--Uncomment the copy-of below if you want to see the intermediate XML $drawing-markup--> 
         <!--<xsl:copy-of select="$drawing-markup"/>--> 

         <!-- Transform XML into SVG --> 
         <xsl:apply-templates select="$drawing-markup"/> 

        </xsl:matching-substring> 
        <xsl:non-matching-substring/> 
       </xsl:analyze-string> 
      </g> 
     </svg> 
    </xsl:template> 

    <!--==========================================--> 
    <!-- Templates to convert the $drawing-markup --> 
    <!--==========================================--> 

    <!--for supported shapes, create the element using 
     lower-case value, and change rectangle to rect 
     for the svg element name !!! if abfrage ob text--> 
    <xsl:template match="GRAPHREP[ELLIPSE | RECTANGLE | ROUNDRECT | LINE | TEXT]"> 
     <xsl:if test="ELLIPSE | RECTANGLE | ROUNDRECT | LINE"> 
      <xsl:element name="{replace(lower-case(local-name(ELLIPSE | RECTANGLE | ROUNDRECT | LINE)), 'rectangle|roundrect', 'rect', 'i')}"> 
       <xsl:attribute name="id" select="concat('id_', generate-id())"/> 
       <xsl:apply-templates /> 
      </xsl:element> 
     </xsl:if> 
     <xsl:if test="TEXT"> 
      <xsl:element name="{lower-case(local-name(TEXT))}"> 
       <xsl:attribute name="id" select="concat('id_', generate-id())"/> 
       <xsl:apply-templates /> 
       <!-- Da muss der text aus den quotes rein --> 
      </xsl:element> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="ELLIPSE | RECTANGLE | ROUNDRECT | LINE | TEXT"/> 

    <!-- Just process the content of GRAPHREP. 
     If there are multiple shapes and you want a new 
     <svg><g></g></svg> for each shape, 
     then move it from the template for "/" into this template--> 
    <xsl:template match="GRAPHREP/*"> 
     <xsl:apply-templates select="@*"/> 
    </xsl:template> 

    <xsl:template match="PEN" priority="1"> 
     <!--TODO: test if these attributes exist, if they do, do not create these defaults. 
      Hard-coding for now, to match desired output, since I don't know what the text 
      attributes would be, but could wrap each with <xsl:if test="not(@dasharray)">--> 
     <xsl:attribute name="stroke-dasharray" select="'null'"/> 
     <xsl:attribute name="stroke-linjoin" select="'null'"/> 
     <xsl:attribute name="stroke-linecap" select="'null'"/> 
     <xsl:apply-templates select="@*"/> 
    </xsl:template> 

    <!-- conterts @color => @stroke --> 
    <xsl:template match="PEN/@color"> 
     <xsl:attribute name="stroke" select="."/> 
    </xsl:template> 

    <!--converts @w => @stroke-width --> 
    <xsl:template match="PEN/@w"> 
     <xsl:attribute name="stroke-width" select="."/> 
    </xsl:template> 

    <!--converts @color => @fill and replaces $ with # --> 
    <xsl:template match="FILL/@color"> 
     <xsl:attribute name="fill" select="translate(., '$', '#')"/> 
    </xsl:template> 

    <!--converts @h => @font-size !!noch mit text verbinden --> 
    <xsl:template match="FONT/@h"> 
     <xsl:attribute name="font-size" select="."/> 
    </xsl:template> 

    <!--converts @color => @fill !!noch mit text verbinden --> 
    <xsl:template match="FONT/@color"> 
     <xsl:attribute name="fill" select="translate(., '$', '#')"/> 
    </xsl:template> 

    <!-- converts @x => @cx with hard-coded values. 
     May want to use value from text, but matching your example--> 
    <xsl:template match="ELLIPSE/@x | ELLIPSE/@y"> 
     <!--not sure if there was a relationship between ELLIPSE x:0pt y:0pt, and why 0pt would be 250, 
      but just an example...--> 
     <xsl:attribute name="c{name()}" select="."/> 
    </xsl:template> 

    <xsl:template match="RECTANGLE/@w | ROUNDRECT/@w"> 
     <xsl:attribute name="{name()}idth" select="."/> 
    </xsl:template> 

    <xsl:template match="RECTANGLE/@h | ROUNDRECT/@h"> 
     <xsl:attribute name="{name()}eight" select="."/> 
    </xsl:template> 

    <xsl:template match="LINE/@x | LINE/@y"> 
     <xsl:attribute name="{name()}" select="."/> 
    </xsl:template> 

    <xsl:template match="TEXT/@x | TEXT/@y"> 
     <xsl:attribute name="{name()}" select="."/> 
    </xsl:template> 

</xsl:stylesheet> 

Редактировать: Нужный выход с вторым входом будет выглядеть так:

<?xml version="1.0" encoding="UTF-8"?> 
<svg xmlns:local="local" 
    xmlns:svg="http://www.w3.org/2000/svg" 
    width="640" 
    height="480"> 
    <g> 
     <ellipse id="id_d2e0" 
       stroke-dasharray="null" 
       stroke-linjoin="null" 
       stroke-linecap="null" 
       stroke="#000000" 
       stroke-width="2" 
       fill="#ff7f00" 
       cx="0" 
       cy="0" 
       rx="50" 
       ry="50"/> 
     <ellipse id="id_d2e6" 
       stroke-dasharray="null" 
       stroke-linjoin="null" 
       stroke-linecap="null" 
       stroke="#000000" 
       stroke-width="2" 
       fill="#ff7f00" 
       cx="0" 
       cy="0" 
       rx="30" 
       ry="30"/> 
    </g> 
</svg> 

SVG должны иметь 2 различных эллипсов.

+1

Можете ли вы изменить свой вопрос, чтобы показать вывод, который вы ожидаете в этом случае? Спасибо! –

+0

Является ли формат всегда атрибутами PEN Атрибуты FILL SomeShape', то есть любой форме предшествует строка 'PEN' и строка' FILL', которая определяет его штрих и заливку? Или может ли линия PEN и/или FILL определять штрих и заполнять различные формы, которые следуют? –

ответ

1

Вот пример, который производит два SVG формы с необходимыми атрибутами:

<?xml version="1.0" encoding="UTF-8"?> 
<!-- Ansatz mit Hilfe von 
http://stackoverflow.com/questions/34682331/xslt-2-0-transform-notation-in-plain-text-to-svg --> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:local="local" 
    exclude-result-prefixes="xs" 
    version="2.0" 
    xmlns:svg="http://www.w3.org/2000/svg"> 
    <xsl:output indent="yes"/> 

<xsl:variable name="drawing-text"> 
GRAPHREP 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:50pt ry:50pt 
PEN color:$000000 w:2pt 
FILL color:$ff7f00 
ELLIPSE x:0pt y:0pt rx:30pt ry:30pt 

</xsl:variable> 
<!-- 
<xsl:param name="drawing-text" /> 
    --> 
    <!--matches sequences of UPPER-CASE letters --> 
    <xsl:variable name="label-pattern" select="'[A-Z]+'"/> 
    <!--matches the "attributes" in the line i.e. w:2pt, 
     has two capture groups (1) => attribute name, (2) => attribute value --> 
    <xsl:variable name="attribute-pattern" select="'\s?(\S+):(\S+)'"/> 
    <!--matches a line of data for the drawing text, 
     has two capture groups (1) => label, (2) attribute data--> 
    <xsl:variable name="line-pattern" select="concat('(', $label-pattern, ')\s(.*)\n?')"/> 
    <!-- Text in quotes holen--> 
    <xsl:variable name="text-pattern" select="'&quot;(.*?)&quot;'"/> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/" name="main"> 
     <svg width="640" height="480"> 
      <g> 
       <!-- Find the text patterns indicating the shape --> 
       <!--Replaced unparsed-text() with local variable for testing     
       select="unparsed-text('drawing.txt')" --> 
       <xsl:analyze-string select="$drawing-text" 
        regex="{concat('(', $label-pattern, ')\n((', $line-pattern, ')+)\n?')}"> 
        <xsl:matching-substring> 
         <!--Convert text to XML --> 
         <xsl:variable name="drawing-markup" as="element()"> 
          <!--Create an element for this group, using first matched pattern as the element name 
           (i.e. GRAPHREP => <GRAPHREP>) --> 
          <xsl:element name="{regex-group(1)}"> 
           <!--split the second matched group for this shape into lines by breaking on newline--> 
           <xsl:variable name="lines" select="tokenize(regex-group(2), '\n')"/> 
           <xsl:for-each select="$lines"> 
            <!--for each line, run through this process to create an element with attributes 
             (e.g. FILL color:$frf7f00 => <FILL color=""/> 
            --> 
            <xsl:analyze-string select="." regex="{$line-pattern}"> 
             <xsl:matching-substring> 
              <!--create an element using the UPPER-CASE label starting the line --> 
              <xsl:element name="{regex-group(1)}"> 
               <!-- capture each of the attributes --> 
               <xsl:analyze-string select="regex-group(2)" regex="\s?(\S+):(\S+)"> 
                <xsl:matching-substring> 
                <!--convert foo:bar into attribute foo="bar", 
                  translate $ => # 
                  and remove the letters 'p' and 't' by translating into nothing"--> 
                <xsl:attribute name="{regex-group(1)}" select="translate(regex-group(2), '$pt', '#')"/> 
                </xsl:matching-substring> 
                <xsl:non-matching-substring/> 
               </xsl:analyze-string> 
              </xsl:element> 
             </xsl:matching-substring> 
             <xsl:non-matching-substring/> 
            </xsl:analyze-string> 
           </xsl:for-each> 
          </xsl:element> 
         </xsl:variable> 
         <!--Uncomment the copy-of below if you want to see the intermediate XML $drawing-markup--> 
         <xsl:copy-of select="$drawing-markup"/> 

         <!-- Transform XML into SVG --> 
         <xsl:apply-templates select="$drawing-markup"/> 

        </xsl:matching-substring> 
        <xsl:non-matching-substring/> 
       </xsl:analyze-string> 
      </g> 
     </svg> 
    </xsl:template> 

    <!--==========================================--> 
    <!-- Templates to convert the $drawing-markup --> 
    <!--==========================================--> 

    <xsl:template match="GRAPHREP"> 
     <xsl:for-each-group select="*" group-starting-with="PEN"> 
      <xsl:apply-templates select="current-group()[not(self::PEN | self::FILL)]"/> 
     </xsl:for-each-group> 
    </xsl:template> 

    <xsl:template match="RECTANGLE | ROUNDRECT"> 
     <rect> 
      <xsl:attribute name="id" select="concat('id_', generate-id())"/> 
      <xsl:apply-templates select="@*, current-group()[self::PEN], current-group()[self::FILL]"/>   
     </rect>   
    </xsl:template> 

    <xsl:template match="ELLIPSE | LINE | TEXT"> 
     <xsl:element name="{lower-case(local-name())}"> 
      <xsl:attribute name="id" select="concat('id_', generate-id())"/> 
      <xsl:apply-templates select="@*, current-group()[self::PEN], current-group()[self::FILL]/@*"/>   
     </xsl:element> 
    </xsl:template> 


    <xsl:template match="PEN" priority="1"> 
     <!--TODO: test if these attributes exist, if they do, do not create these defaults. 
      Hard-coding for now, to match desired output, since I don't know what the text 
      attributes would be, but could wrap each with <xsl:if test="not(@dasharray)">--> 
     <xsl:attribute name="stroke-dasharray" select="'null'"/> 
     <xsl:attribute name="stroke-linjoin" select="'null'"/> 
     <xsl:attribute name="stroke-linecap" select="'null'"/> 
     <xsl:apply-templates select="@*"/> 
    </xsl:template> 

    <!-- conterts @color => @stroke --> 
    <xsl:template match="PEN/@color"> 
     <xsl:attribute name="stroke" select="."/> 
    </xsl:template> 

    <!--converts @w => @stroke-width --> 
    <xsl:template match="PEN/@w"> 
     <xsl:attribute name="stroke-width" select="."/> 
    </xsl:template> 

    <!--converts @color => @fill and replaces $ with # --> 
    <xsl:template match="FILL/@color"> 
     <xsl:attribute name="fill" select="translate(., '$', '#')"/> 
    </xsl:template> 

    <!--converts @h => @font-size !!noch mit text verbinden --> 
    <xsl:template match="FONT/@h"> 
     <xsl:attribute name="font-size" select="."/> 
    </xsl:template> 

    <!--converts @color => @fill !!noch mit text verbinden --> 
    <xsl:template match="FONT/@color"> 
     <xsl:attribute name="fill" select="translate(., '$', '#')"/> 
    </xsl:template> 

    <!-- converts @x => @cx with hard-coded values. 
     May want to use value from text, but matching your example--> 
    <xsl:template match="ELLIPSE/@x | ELLIPSE/@y"> 
     <!--not sure if there was a relationship between ELLIPSE x:0pt y:0pt, and why 0pt would be 250, 
      but just an example...--> 
     <xsl:attribute name="c{name()}" select="."/> 
    </xsl:template> 

    <xsl:template match="RECTANGLE/@w | ROUNDRECT/@w"> 
     <xsl:attribute name="{name()}idth" select="."/> 
    </xsl:template> 

    <xsl:template match="RECTANGLE/@h | ROUNDRECT/@h"> 
     <xsl:attribute name="{name()}eight" select="."/> 
    </xsl:template> 

    <xsl:template match="LINE/@x | LINE/@y"> 
     <xsl:attribute name="{name()}" select="."/> 
    </xsl:template> 

    <xsl:template match="TEXT/@x | TEXT/@y"> 
     <xsl:attribute name="{name()}" select="."/> 
    </xsl:template> 

</xsl:stylesheet> 

 Смежные вопросы

  • Нет связанных вопросов^_^