【问题标题】:Styling a nested XML element with XSLT?使用 XSLT 设置嵌套 XML 元素的样式?
【发布时间】:2015-09-09 22:07:08
【问题描述】:

我是一名印刷设计师,正在制作一本旅行指南,我们最近开始使用 XML 标记的内容和 XSLT 样式来管理该指南。除了这个让我们束手无策的小问题之外,它大部分都有效!我们有一些应显示为“子”列表的子景点列表,我们可以在 InDesign 布局中设置不同的样式,并且通过在 MainAttraction 标记中记录其“父”景点的值,在 XML 中对其进行注释。

我的理解是,我们需要 .XSL 来注意 MainAttraction 标签中是否有值,如果有,则将与该景点关联的元素拉出到不同的容器标签下,以便我们可以设置它们的样式不同。在进行了一些基本培训和谷歌搜索之后,我没有任何运气为此编写语法。

这是我正在试验的,它可以正确提取除子景点之外的所有内容(它们列在与其关联的父列表的景点标签中):

XSLT

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">

    <Cities>
        <xsl:for-each select="Root/City">
            <City>
                <City_Name>
                    <xsl:value-of select="City_Name"/>
                </City_Name>
                <xsl:text>&#xa;</xsl:text>
                <City_Stats>
                    <xsl:text>POP. </xsl:text>
                    <xsl:value-of select="Population"/>
                    <xsl:text>  ALT. </xsl:text>
                    <xsl:value-of select="Altitude"/>
                    <xsl:text>  MAP </xsl:text>
                    <xsl:value-of select="Map_Grid_Location"/>
                </City_Stats>
                <xsl:text>&#xa;</xsl:text>

                <Visitor_Info>

                    <Visitor_Center>
                        <xsl:value-of select="Visitor_Center"/><xsl:text>: </xsl:text>
                    </Visitor_Center>

                    <Visitor_Information>

                        <xsl:value-of select="Visitor_Information"/><xsl:text> </xsl:text>
                        <xsl:value-of select="Address"/>
                        <xsl:text> </xsl:text>

                        <xsl:value-of select="normalize-space(Phone1)"/>
                            <xsl:if test="string-length(Phone2) &gt; 0">
                            <xsl:text> or </xsl:text>
                            <xsl:value-of select="Phone2"/>
                            </xsl:if>
                            <xsl:if test="string-length(Phone1) &gt; 0">
                            <xsl:text>. </xsl:text>
                            </xsl:if>


                        <xsl:value-of select="normalize-space(Website1)"/>
                            <xsl:if test="string-length(Website2) &gt; 0">
                            <xsl:text> or </xsl:text>
                            <xsl:value-of select="Website2"/>
                            </xsl:if>
                            <xsl:if test="string-length(Website1) &gt; 0">
                            <xsl:text>. </xsl:text>
                            </xsl:if>


                        </Visitor_Information>

                    </Visitor_Info>
                <xsl:text>&#xa;</xsl:text>

                <Description>
                    <xsl:value-of select="Description"/>
                </Description>
                    <xsl:text>&#xa;</xsl:text>

                <Attractions>
                    <xsl:apply-templates select="Attraction"/>
                </Attractions>



            </City>

        </xsl:for-each>

    </Cities>

    </xsl:template>


    <xsl:template match="Attraction">

        <Attraction>

                    <Attraction_Title>
                        <xsl:value-of select="normalize-space(Attraction_Title)"/>
                    </Attraction_Title>
                    <xsl:text>&#8212;</xsl:text>

                    <xsl:value-of select="Desc"/><xsl:text> </xsl:text>

                    <xsl:value-of select="normalize-space(Admissions)"/>
                        <xsl:if test="string-length(Admissions) &gt; 0">
                            <xsl:text>. </xsl:text>
                        </xsl:if>

                    <xsl:value-of select="normalize-space(Address)"/>
                    <xsl:if test="string-length(Address) &gt; 0">
                        <xsl:text>. </xsl:text>
                    </xsl:if>

                <xsl:value-of select="normalize-space(Directions)"/>
                <xsl:if test="string-length(Directions) &gt; 0">
                    <xsl:text>. </xsl:text>
                </xsl:if>

                <xsl:value-of select="normalize-space(Phone)"/>
                <xsl:if test="string-length(AltPhone) &gt; 0">
                    <xsl:text> or </xsl:text>
                    <xsl:value-of select="normalize-space(AltPhone)"/>
                </xsl:if>

                <xsl:if test="string-length(Phone) &gt; 0">
                    <xsl:text>. </xsl:text>
                </xsl:if>

                <xsl:value-of select="normalize-space(WebAddress)"/>
                <xsl:if test="string-length(WebAddress2) &gt; 0">
                    <xsl:text> or </xsl:text>
                    <xsl:value-of select="normalize-space(WebAddress2)"/>
                </xsl:if>

                <xsl:if test="string-length(WebAddress) &gt; 0">
                    <xsl:text>. </xsl:text>
                </xsl:if>

                <xsl:value-of select="normalize-space(Email)"/>
                    <xsl:if test="string-length(Email) &gt; 0">
                        <xsl:text>. </xsl:text>
                    </xsl:if>

                    <xsl:if test="string-length(SeeAlso) &gt; 0">
                        <xsl:text> </xsl:text>
                        <xsl:text>See </xsl:text>
                        <xsl:value-of select="normalize-space(SeeAlso)"/>
                        <xsl:text>. </xsl:text>
                    </xsl:if>

                <xsl:text>&#xa;</xsl:text>

        </Attraction>

    </xsl:template>

    <xsl:template match="SubAttraction">

        <SubAttraction>

            <xsl:if test="string-length(MainAttraction) &gt; 0">

                <xsl:text>&#9;</xsl:text>

                    <SubAttraction_Title>
                        <xsl:value-of select="normalize-space(Attraction_Title)"/>
                    </SubAttraction_Title>
                    <xsl:text>&#8212;</xsl:text>

                    <xsl:value-of select="Desc"/><xsl:text> </xsl:text>

                    <xsl:value-of select="normalize-space(Admissions)"/>
                        <xsl:if test="string-length(Admissions) &gt; 0">
                            <xsl:text>. </xsl:text>
                        </xsl:if>

                    <xsl:value-of select="normalize-space(Address)"/>
                    <xsl:if test="string-length(Address) &gt; 0">
                        <xsl:text>. </xsl:text>
                    </xsl:if>

                <xsl:value-of select="normalize-space(Directions)"/>
                <xsl:if test="string-length(Directions) &gt; 0">
                    <xsl:text>. </xsl:text>
                </xsl:if>

                <xsl:value-of select="normalize-space(Phone)"/>
                <xsl:if test="string-length(AltPhone) &gt; 0">
                    <xsl:text> or </xsl:text>
                    <xsl:value-of select="normalize-space(AltPhone)"/>
                </xsl:if>

                <xsl:if test="string-length(Phone) &gt; 0">
                    <xsl:text>. </xsl:text>
                </xsl:if>

                <xsl:value-of select="normalize-space(WebAddress)"/>
                <xsl:if test="string-length(WebAddress2) &gt; 0">
                    <xsl:text> or </xsl:text>
                    <xsl:value-of select="normalize-space(WebAddress2)"/>
                </xsl:if>

                <xsl:if test="string-length(WebAddress) &gt; 0">
                    <xsl:text>. </xsl:text>
                </xsl:if>

                <xsl:value-of select="normalize-space(Email)"/>
                    <xsl:if test="string-length(Email) &gt; 0">
                        <xsl:text>. </xsl:text>
                    </xsl:if>

                <xsl:text>&#xa;</xsl:text>

            </xsl:if>

        </SubAttraction>

    </xsl:template>

</xsl:stylesheet>

XML INPUT SAMPLE(请注意,子景点示例,Fredda Turner Durham Children's Museum,在其主要景点标签中具有价值,并嵌套在其父列表的景点标签中)

<?xml version="1.0" encoding="UTF-8"?>

<Root>
    <City>
        <City_Name>MIDLAND</City_Name>
        <Region>BIG BEND COUNTRY</Region>
        <Population>127,598</Population>
        <Altitude>2,891</Altitude>
        <Map_Grid_Location>L-9/KK-4</Map_Grid_Location>
        <Visitor_Center>Midland Visitors Center</Visitor_Center>                    <Visitor_Information>Midland Convention &amp; Visitors Bureau: Open 8 a.m.-5 p.m. Mon.-Sat. 109 N Main St. 800/624-6435.</Visitor_Information><Address>1406 W. I-20 (Exit 136).</Address><Hours>Open 9 a.m.-5 p.m. Mon.-Sat.</Hours><Phone1>432/683-2882</Phone1><Phone2>800/624-6435</Phone2><Website1>&lt;a href="http://www.visitmidlandtexas.com" &gt;www.visitmidlandtexas.com&lt;/a&gt;</Website1><Website2></Website2><Email></Email>
        <CityId>MIDLAND</CityId>
        <Description>Description text goes here.</Description>

        <Attraction>
            <Attraction_Title>Haley Library &amp; History Center</Attraction_Title>
            <Desc>Description text goes here. </Desc>
            <Admissions>Donations accepted.</Admissions>
            <Hours>Open 9 a.m.-5 p.m. Mon.-Fri.</Hours>
            <Address>1805 W. Indiana Ave.</Address>
            <Directions></Directions>
            <Phone>432/682-5785</Phone>
            <AltPhone></AltPhone>
            <WebAddress></WebAddress>
            <WebAddress2></WebAddress2>
            <Email></Email>
            <SeeAlso></SeeAlso>
            <MainAttraction></MainAttraction>
        </Attraction>

        <Attraction>
            <Attraction_Title>I-20 Wildlife Preserve &amp; Jenna Welch Nature Study Center</Attraction_Title>
            <Desc>Description text goes here.</Desc>
            <Admissions></Admissions>
            <Hours>Open dusk–dawn daily.</Hours>
            <Address>2201 S. Midland Dr.</Address>
            <Phone>432/853-9453</Phone>
            <AltPhone></AltPhone>
            <WebAddress>www.i20wildlifepreserve.org</WebAddress>
            <WebAddress2></WebAddress2>
            <Email></Email>
            <SeeAlso></SeeAlso>
            <MainAttraction></MainAttraction>
        </Attraction>

        <Attraction>
            <Attraction_Title>Museum of the Southwest</Attraction_Title>
            <Desc>Description text goes here.</Desc>
            <Admissions>Admission charged.</Admissions>
            <Hours>Open 10 a.m.-5 p.m. Tue.-Sat. and 2-5 p.m. Sun.</Hours>
            <Address>1705 W. Missouri.</Address>
            <Directions></Directions>
            <Phone>432/683-2882</Phone>
            <AltPhone></AltPhone>
            <WebAddress>www.museumsw.org</WebAddress>
            <WebAddress2></WebAddress2>
            <Email></Email>
            <SeeAlso></SeeAlso>
            <MainAttraction></MainAttraction>

                <Attraction>
                    <Attraction_Title>Fredda Turner Durham Children's Museum</Attraction_Title>
                    <Desc>Description text goes here.</Desc>
                    <Admissions>Admission charge.</Admissions>
                    <Hours>Open 10 a.m.-5 p.m. Tue.-Sat. and 2-5 p.m. Sun. Free admission on Sundays.</Hours>
                    <Address></Address><Directions></Directions><Phone>432/683-2882</Phone><AltPhone></AltPhone><WebAddress></WebAddress><WebAddress2></WebAddress2><Email></Email><SeeAlso></SeeAlso><MainAttraction>Museum of the Southwest</MainAttraction>

            </Attraction>

        </Attraction>

    </City>

</Root>

当前输出(子景点不显示)

    <?xml version="1.0" encoding="UTF-8"?>
<Cities>
   <City>
      <City_Name>MIDLAND</City_Name>
      <City_Stats>POP. 127,598  ALT. 2,891  MAP L-9/KK-4</City_Stats>
      <Visitor_Info>
         <Visitor_Center>Midland Visitors Center:</Visitor_Center>
         <Visitor_Information>Midland Convention &amp; Visitors Bureau: Open 8 a.m.-5 p.m. Mon.-Sat. 109 N Main St. 800/624-6435. 1406 W. I-20 (Exit 136). 432/683-2882 or 800/624-6435. &lt;a href="http://www.visitmidlandtexas.com" &gt;www.visitmidlandtexas.com&lt;/a&gt;.</Visitor_Information>
      </Visitor_Info>
      <Description>Description text goes here.</Description>
      <Attractions>
         <Attraction>
            <Attraction_Title>Haley Library &amp; History Center</Attraction_Title>
            —Description text goes here.  Donations accepted.. 1805 W. Indiana Ave.. 432/682-5785.
         </Attraction>
         <Attraction>
            <Attraction_Title>I-20 Wildlife Preserve &amp; Jenna Welch Nature Study Center</Attraction_Title>
            —Description text goes here. 2201 S. Midland Dr.. 432/853-9453. www.i20wildlifepreserve.org.
         </Attraction>
         <Attraction>
            <Attraction_Title>Museum of the Southwest</Attraction_Title>
            —Description text goes here. Admission charged.. 1705 W. Missouri.. 432/683-2882. www.museumsw.org.
         </Attraction>
      </Attractions>
   </City>
</Cities>

DESIRED OUTPUT(子景点显示并有自己的容器标签)

<?xml version="1.0" encoding="UTF-8"?>
<Cities>
   <City>
      <City_Name>MIDLAND</City_Name>
      <City_Stats>POP. 127,598  ALT. 2,891  MAP L-9/KK-4</City_Stats>
      <Visitor_Info>
         <Visitor_Center>Midland Visitors Center:</Visitor_Center>
         <Visitor_Information>Midland Convention &amp; Visitors Bureau: Open 8 a.m.-5 p.m. Mon.-Sat. 109 N Main St. 800/624-6435. 1406 W. I-20 (Exit 136). 432/683-2882 or 800/624-6435. &lt;a href="http://www.visitmidlandtexas.com" &gt;www.visitmidlandtexas.com&lt;/a&gt;.</Visitor_Information>
      </Visitor_Info>
      <Description>Description text goes here.</Description>
      <Attractions>
         <Attraction>
            <Attraction_Title>Haley Library &amp; History Center</Attraction_Title>
            —Description text goes here.  Donations accepted.. 1805 W. Indiana Ave.. 432/682-5785.
         </Attraction>
         <Attraction>
            <Attraction_Title>I-20 Wildlife Preserve &amp; Jenna Welch Nature Study Center</Attraction_Title>—Description text goes here. 2201 S. Midland Dr.. 432/853-9453. www.i20wildlifepreserve.org.
         </Attraction>
         <Attraction>
            <Attraction_Title>Museum of the Southwest</Attraction_Title>—Description text goes here. Admission charged.. 1705 W. Missouri.. 432/683-2882. www.museumsw.org.
         </Attraction>
         <SubAttraction>
            <SubAttraction_Title>Fredda Turner Durham Children's Museum</SubAttraction_Title>—Description text goes here. Admission charge.. 432/683-2882.
         </SubAttraction>
     </Attractions>
  </City>
</Cities>

那么我要在这里做什么才能使子景点(在 MainAttraction 字段中具有值的景点)可以被拉入新的容器标签中?我知道我们想为 SubAttractions 创建一个新模板,但我不知道如何只将所需的元素放入其中。如果对于更有经验的人来说不是太难的话,我将非常感谢帮助在这里找到可以插入的东西。

[原始帖子已被编辑以提供更多有用的信息。]

【问题讨论】:

    标签: xml xslt adobe-indesign


    【解决方案1】:

    线

    <xsl:template match="SubAttraction">
    

    不会匹配任何内容,因为输入 xml 中没有 SubAttraction 节点。

    要获得匹配,您需要将其更改为

    <xsl:template match="Attraction[../../Attraction]">
    

    然后添加

    <xsl:apply-templates select="Attraction"/>
    

    行前

    </Attraction>
    

    在您的 xsl:template match="Attraction" 模板中。

    【讨论】:

    • 这有助于我在子景点中设置我需要的标签样式——谢谢!
    • 乐于助人。我可以得到 +1 吗?
    【解决方案2】:

    那么我该怎么做才能使它成为具有 MainAttraction 的吸引力 值会以不同的方式显示、标记和设置样式吗?

    这取决于样式需要有多大的不同。如果它非常不同,您可能希望使用不同的模板来处理每种类型,例如:

    <xsl:template match="Attraction">
        <!-- code to process "regular" attraction -->
    </xsl:template>
    
    <xsl:template match="Attraction[string(MainAttraction)]">
        <!-- code to process "main" attraction -->
    </xsl:template>
    

    否则,您可以使用xsl:choose 和/或xsl:if 在同一模板中的两种类型之间进行分支。


    编辑:

    我在处理这两种类型的方式上看到的唯一区别是包含元素的名称:AttractionSubAttraction

    如果这个观察结果是正确的,我建议您尝试这种方式(最小化到仅对问题至关重要的部分):

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/Root">
        <Cities>
            <xsl:apply-templates select="City"/>
        </Cities>
    </xsl:template>
    
    <xsl:template match="City">
        <City>
            <City_Name>
                <xsl:value-of select="City_Name"/>
            </City_Name>
            <!-- more details here -->
            <Attractions>
                <xsl:apply-templates select="Attraction"/>
            </Attractions>
        </City>
    </xsl:template>
    
    <xsl:template match="Attraction">
        <xsl:variable name="tag">
            <xsl:choose>
                <xsl:when test="string(MainAttraction)">SubAttraction</xsl:when>
                <xsl:otherwise>Attraction</xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:element name="{$tag}">
            <Attraction_Title>
                <xsl:value-of select="normalize-space(Attraction_Title)"/>
            </Attraction_Title>
            <xsl:value-of select="Desc"/>
            <!-- more details here -->
        </xsl:element>
        <xsl:apply-templates select="Attraction"/>
    </xsl:template>
    
    </xsl:stylesheet>
    

    请注意,与您原来的问题不同,您现在将子景点显示为主要景点的子景点。这需要在主要景点的上下文中再次调用xsl:apply-templates select="Attraction"(如上所示)。

    【讨论】:

    • 从问题的描述来看,我肯定会在这里使用单独的模板规则。
    • 子景点和主要景点的样式不会有太大的不同......我们想要的只是在子景点名称之前添加一个缩进并更改字体样式的名字。我认为我真正被挂断的部分是如何将缩进放在子景点名称前面,并根据 MainAttraction 标记中的内容重新标记其名称以进行样式设置。
    • @Inks 恐怕我不明白你的意思(我在你的样式表中看不到字体样式或缩进)。您为什么不编辑您的问题并添加示例的预期输出?
    • @Inks: ... 在 InDesign 布局中 - 您不会对此进行扩展,但您是否有机会使用从标签到段落样式的映射?在这种情况下,您只需将那些不那么主要的景点映射到带有内置缩进的预定义样式。
    • @Jongware 是正确的,我们将 XML 标签映射到 InDesign 中的样式,然后可以在那里应用缩进。但是,在XSL 转换之前,子景点与主要景点的标签相同,因此我们无法仅将子景点隔离为不同的样式。唯一的区别是子景点在 MainAttraction 标签中有一个值。目前,子景点根本没有出现在我们原本可以正常工作的输出中,出于某种原因我无法确定。
    猜你喜欢
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    相关资源
    最近更新 更多