Set default values from another xml for empty node

2019-08-06 00:45发布

Given:

File with data:

<doc>
     <a>some text(<p>text here</p>) or blank</a>
     <b>same</b>
</doc>

File with default values:

<doc>
     <a><p>Dummy text</p></a>
     <b><p>Dummy text</p></b>
</doc>

I got this xslt to get the defaults from the second file:

$file = file path with default values

<a>
    <xsl:choose>
        <xsl:when test="//a!= ''">
            <xsl:copy-of select="//a/p" />
        </xsl:when>
        <xsl:otherwise>
              <xsl:copy-of select="document($file)//a/p" />
        </xsl:otherwise>
    </xsl:choose>
</a>

With this it works well and all, the only problem is that I would like to make an iteration through the xml nodes and make an automated process to improve scalability and save time entering every time the same condition fro each node. But I can't find a way to use the document() function with variables for the xpath, document($file)$nodexpath doesn't work.

I might be missing something, just started recently with xslt, if any of you could give me some advice I would appreciate It greatly.

Thanks in advance.

EDIT: The actual data resembles more an xml like this, it can have more deepth levels.

   <doc>
       <object>
          <group1> 
              <a>(<p>text here</p> or blank)</a>
              <b>(<p>text here</p> or blank)</b>
              <c>
                 <c1>(<p>text here</p> or blank)</c1>
                 <c2>(<p>text here</p> or blank)</c2>
              </c>
          </group1>
          <group2>
              <d>(<p>text here</p> or blank)</d>
          </group2>
       </object>
    </doc>

标签: xml xslt xpath
2条回答
女痞
2楼-- · 2019-08-06 01:28

I've finally resolved it, I'm posting my solution here, thanks Daniel for your answer, it helped me a lot:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/*">
        <doc xml:lang="es">
            <object>
                <xsl:apply-templates select="*"/>
            </object>
        </doc>
    </xsl:template> 

    <xsl:template match="*">
        <xsl:copy>
            <xsl:choose>
              <xsl:when test="current() != ''">
                <xsl:choose>
                    <xsl:when test="self::p">
                        <xsl:copy-of select="node()"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="*"/>
                    </xsl:otherwise>
                </xsl:choose>
              </xsl:when>
              <xsl:otherwise>
                <xsl:variable name="file" select="document('template.xml')"/>
                <xsl:copy-of select ="$file//*[name()=name(current())]/p"/>
              </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
查看更多
手持菜刀,她持情操
3楼-- · 2019-08-06 01:34

You could try matching any element that doesn't contain a child element or text and pull the default based off of the name.

There doesn't seem to be a reason to try to match xpaths based on your example. If your actual data is more complicated, update your question and I can update my answer.

Example:

XML Input (Added empty a and b to get default values.)

<doc>
    <a>some text(<p>text here</p>) or blank</a>
    <a/>
    <b>same</b>
    <b/>
</doc>

so_defaults.xml

<doc>
    <a><p>Dummy text for "a".</p></a>
    <b><p>Dummy text for "b".</p></b>
</doc>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="defaults" select="document('so_defaults.xml')"/>

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

    <xsl:template match="*[not(*) and not(text())]">
        <xsl:copy>
            <xsl:apply-templates select="$defaults/*/*[name()=name(current())]/*"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Output

<doc>
   <a>some text(<p>text here</p>) or blank</a>
   <a>
      <p>Dummy text for "a".</p>
   </a>
   <b>same</b>
   <b>
      <p>Dummy text for "b".</p>
   </b>
</doc>
查看更多
登录 后发表回答