dita-ot / dita-ot

DITA Open Toolkit — the open-source publishing engine for content authored in the Darwin Information Typing Architecture.
https://www.dita-ot.org
Apache License 2.0
404 stars 196 forks source link

Element conref does not properly support specialization #1884

Open raducoravu opened 9 years ago

raducoravu commented 9 years ago

For example I cannot make a conref from an OL to a STEPS or from a PH to a B element.

Let's say for simplicity sake that I have a bold element defined in a topic:

<b id="bold">usually</b>

According to the specification I can make a conref from a base element to a more specialized element (and not the other way around).

So I can do this in another topic:

<ph conref="../tasks/pruning.dita#taskId/bold"/>

But although this is a valid construct the publishing does not expand the conref + it reports as an error that it cannot find the target ID.

The XSLT stylesheet which is used for resolving conrefs is DITA-OT\xsl\preprocess\conrefImpl.xsl and it has a template which resolves conrefs:

<xsl:template match="*[@conref][@conref!=''][not(@conaction)]" priority="10">

and that template matches target element IDs using an XPath like:

<xsl:variable name="target" select="key('id', $elemid)[local-name()=$element][ancestor::*[contains(@class, ' topic/topic ')][1][@id=$topicid]]"/>

thus forcing the name of the source element to be equal to the name of the target element. In my opinion it should look at the @class attributes set on source and target elements and allow the conref if the source is a generalization of the target or disallow it with a meaningful message if it is not.

shaneataylor commented 8 years ago

A common use case is step elements that need to be substeps in certain contexts.

robander commented 8 years ago

I don't think the language of the specification allows for conref between <steps> and <substeps> (in either direction). It explicitly allows for the @conref attribute on a more general element to a reference an @id on a more specialized element, such as <ol> referencing <steps> (steps are specialized from ordered lists). This works because of the core rule of specialization, that the more specialized element cannot be more permissive than the more general element.

Conref does not allow for reuse between two distinct elements that have the same ancestor, but have branched off in different directions. In that case there is no guarantee of compatibility for either side of the equation. In the specific case of a <step> element that needs to be a substep, <step> itself allows several child elements that are not allowed in <substep>, so the reuse would result in invalid constructs.

raducoravu commented 8 years ago

:+1: Our tech writer was using "ph" with conrefs to "codeph" elements. The transformation complained that the target element could not be found. It should have worked.

raducoravu commented 8 years ago

👍 One of our users tries to conref from a topicref to a topicgroup in a DITA Map. Fails for the same reason.

robander commented 1 year ago

Tested this with the 4.0 release and I think it is obsolete. I'm able to pull codeph in with @conref on a phrase, able to pull steps in with @conref on an ordered list, and able to pull step in with conref on li. As expected, I'm not able to do the reverse (I can't pull the general element in with <codeph conref="#./ph"/>)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA Task//EN" "task.dtd">
<task id="testpage">
    <title>Testing of conrefs</title>
    <taskbody>
        <context>
            <ul id="ul_lpp_qrj_pvb">
                <li>Try reusing stuff</li>
                <li>Here is a phrase: <ph id="ph">reuse a ph element</ph></li>
                <li>here is a codeph: <codeph id="codeph">reuse a codeph</codeph></li>
                <li>here is an ordered list: <ol id="ol">
                        <li id="li">one item</li>
                        <li>second item</li>
                    </ol></li>
            </ul>
        </context>
        <steps id="steps">
            <step id="step">
                <cmd>one step</cmd>
            </step>
            <step>
                <cmd>two step</cmd>
            </step>
        </steps>
        <result id="result_hjg_qrj_pvb">
            <p>see what we get.</p>
            <ul id="ul_m3t_5rj_pvb">
                <li>Pull phrase into phrase, should work: <ph conref="#./ph"/></li>
                <li>Pull codeph into phrase, should work: <ph conref="#./codeph"/></li>
                <li>Pull phrase into codeph, should NOT work: <codeph conref="#./ph"/></li>
                <li>Pull codeph into codeph, should work: <codeph conref="#./codeph"/></li>
                <li>Pull list into list: <ol conref="#./ol"><li/></ol></li>
                <li>Pull steps into list: <ol conref="#./steps"><li/></ol></li>
                <li>OK, now use sublist to test list items
                    <ol>
                        <li>Test pulling li into li, then step into li, both should work</li>
                        <li conref="#./li"/>
                        <li conref="#./step"/>
                    </ol></li>
            </ul>
        </result>
    </taskbody>
</task>
robander commented 1 year ago

There is still a very minor issue I think in that the error message for codeph reference to ph is misleading - it says that the target does not exist. In fact it exists it's just not a legal reference: [conref] file:/Users/robander/dita-ot-4.0/tests/1884/testpage.dita:30:87: [DOTX010E][ERROR]: Unable to find target for conref="#testpage/ph".