• ,

level33.lesson10.bonus01

Программа работает. Комментарии вставляет с форматированием. Валидатор не принимает.
Хуберт писал, что задачи 33 уровня пофикшены, но на статистике решения этой задачи данное событие не отразилось.

/* Комментарий внутри xml
Реализовать метод toXmlWithComment, который должен возвращать строку - xml представление объекта obj.
В строке перед каждым тэгом tagName должен быть вставлен комментарий comment.
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.

Пример вызова:  toXmlWithComment(firstSecondObject, "second", "it's a comment")
Пример результата:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
</first>
*/

85 комментариев

Diana
Прекрасно!
Есть 2 замечания:
1) Вы портите одиночные теги, например
<someTag/>
превращается в
<someTag></someTag>

2) Первая строка
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
Превращается в
<?xml version="1.0" encoding="UTF-8"?>

А с комментами все прекрасно, БРАВО!

Код затру :)
kolust
Дорогая diana подскажите пожалуйста:
если строка такая
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<second>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
</second>
, то нужно ли вставлять коммент перед первым
<second>
или комменты вставлять только если строка типа
<second>some string</second>
, и правильно ли валидатор принимает решение

Заранее спасибо
AlexY
Я еще не сдал, но думаю что нужно перед всеми вставлять.
kolust
  • kolust
  • 0
  • Комментарий отредактирован 2015-01-22 01:32:29 пользователем kolust
Привет.Парюсь над этой задачей, может вдвоем проанализируем? Решил протестировать свое решение на объекте и подумал «А как нам в него вставить тег CDATA?».В метод нам приходит только объект
— значит CDATA в нем вписывается где то в самом классе, значит аннотацией.Мы работаем с JAXB и все мои поиски в гугле аннотации, которая добавила бы CDATA при сериализации, оказались безуспешными!!! В готовом представлении объекта в xml отыскать CDATA не проблема, проблема как описать класс так, чтобы он содержал CDATA.Может ты вкурсе как добавить CDATA в класс объекта аннотациями или может каким то другим способом?
Если можеш скинь свой код, имейл в личных даных
Diana
надо вставить перед всеми
<second


Вот пример:

    <!--it's a <second> tag comment-->
    <second/>
    <!--it's a <second> tag comment-->
    <second>some string</second>
    <!--it's a <second> tag comment-->
    <second><![CDATA[need CDATA comment because of < and > signs. Don't need before that <second> placed inside CDATA]]></second>


Как определить, нужна ли CDATA?? :) Почитать про CDATA.
Например, если в тексте есть знаки больше/меньше, то тег CDATA ставить необходимо.
kolust
Спасибо за ответ, я понимаю что такое CDATA, вопрос в том как вложить его на этапе сериализации, ведь нам в метод передали объект и мы не знаем где в нем будет находится CDATA.Мы можем сериализовать его и если нужно вставить CDATA вручную, но когда все в формате xml.Вопрос — как описать класс так, чтобы при сериализации CDATA создавался сам???JAXB не умеет вставлять CDATA при сериализации!(ДОпустим я хочу протестировать свою программу.Как мне создать объект с CDATA???).Заранее спасибо за помощь
Diana
Вам не нужно описывать класс. Для тестов используется ДРУГОЙ класс, с другим именем, другими полями,… У Вас к нему доступа нет.
Если текстовое значение любого поля класса содержит спецсимволы xml, то его необходимо завернуть в CDATA
kolust
вопрос в том как завернуть — при маршалинге(если да то подскажите ресурс) или в готовом xml проверить на наличие спецсимволов и создать cdata простым редактированием? Есть ли способ автоматически заворачивать в cdata при наличии спецсимволов?
demi
Условие для задачи —
/* Комментарий внутри xml
Реализовать метод toXmlWithComment, который должен возвращать строку — xml представление объекта obj.
В строке перед каждым тэгом tagName должен быть вставлен комментарий comment.
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.
*/
В условии не описана прокомментированная вами ситуация — «Если текстовое значение любого поля класса содержит спецсимволы xml, то его необходимо завернуть в CDATA»
Предлагается точно описывать условия задачи!
Diana
see
AlexY
  • AlexY
  • 0
  • Комментарий отредактирован 2015-01-19 00:35:14 пользователем AlexY
Спасибо за лестный отзыв. К тому же вдвойне приятно это слышать от профессионального программиста. :)

По замечаниям не совсем понял:
1) Добавление комментов не влияет на одиночные теги. Вот пример работы программы:
<code><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<first>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
    <emptyString xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
    <string>Hello</string>
</first></code>
Возможность добавлять комменты к одиночным тегам и тегам с атрибутами добавил (поменял логику на регулярку). Валидатор все равно не принимает. Вы имеете ввиду что при маршалинге можно указать способ формирования одиночных тегов?

2) У меня xml создает с первой строчкой
<code><?xml version="1.0" encoding="UTF-8" standalone="yes"?></code>
И после добавления комментов все так и остается.
Вы имеете ввиду что нужно создавать xml с полем standalone=«no»? Или нужно уже в готовом xml поменять yes на no?
Diana
Реализация — на Ваше усмотрение. Главное, чтоб в результирующей строке было standalone=«no»
iZulrad
Можно пример вывода с тегом CDATA?
Входные данные №1
<?xml version="1.0"?><second><![CDATA[<second>some string</second> ]]><second>some string</second><second text="TEXT"/></second>

Результат №1
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--it's a comment--><second><![CDATA[<second>some string</second> ]]><!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second text="TEXT"/>
</second>

Входные данные №2
<?xml version="1.0"?><first><![CDATA[<second>some string</second> ]]><second>some string</second><second text="TEXT"/></first>

Результат №2
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first><![CDATA[<second>some string</second> ]]><!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second text="TEXT"/>
</first>

Входные данные №3
@XmlRootElement(name = "first")
public class FirstSecondObject {
    @XmlElement(name = "second")
    public List<String> seconds = new ArrayList<String>() {
        {
            add("some string");
            add("some string");
        }
    };
}

Результат №3
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
</first>

В примере результата? в декларации xml? пропущен "?" в конце?
iZulrad
В примере результата, в декларации xml, пропущен "?" в конце?*
iZulrad
Входные №4
@XmlRootElement(name = "first")
public class FirstSecondObject {

    @XmlJavaTypeAdapter(XmlAdapterCDATA.class)
    @XmlElement(name = "second")
    public List<String> seconds = new ArrayList<String>() {
        {
            add("<second>");
            add("some string");
        }
    };

    @XmlJavaTypeAdapter(XmlAdapterCDATA.class)
    public String line = "<second>";
}

public class XmlAdapterCDATA extends XmlAdapter<String, String> {
    @Override
    public String marshal(String value) throws Exception {
        return "<![CDATA[" + value + "]]>";
    }
    @Override
    public String unmarshal(String value) throws Exception {
        return value;
    }
}

Результат №4
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second><![CDATA[<second>]]></second>
    <!--it's a comment-->
    <second><![CDATA[some string]]></second>
    <line><![CDATA[<second>]]></line>
</first>
iZulrad
Это
@XmlRootElement(name = "first")
public class FirstSecondObject {

    @XmlJavaTypeAdapter(XmlAdapterCDATA.class)
    @XmlElement(name = "second")
    public List<String> seconds = new ArrayList<String>() {
        {
            add("<second>");
            add("some string");
        }
    };

    @XmlElement(name = "third")
    public List<String> thirds = new ArrayList<String>() {
        {
            add("TEST");
            add("some string");
            add("some string");
            add("<![CDATA[<second>]]");
        }
    };

    @XmlJavaTypeAdapter(XmlAdapterCDATA.class)
    public String line = "<second>";

    @Override
    public String toString() {
        return "FirstSecondObject{" +
                "seconds=" + seconds +
                ", thirds=" + thirds +
                ", line='" + line + '\'' +
                '}';
    }
}

с помощью этого
public class XmlAdapterCDATA extends XmlAdapter<String, String> {
    @Override
    public String marshal(String value) throws Exception {
        return "<![CDATA[" + value + "]]>";
    }
    @Override
    public String unmarshal(String value) throws Exception {
        return value.substring(9, value.length()-3);
    }
}

конфертируем в xml
toXmlWithComment(new FirstSecondObject(), "second", "it's a comment")

пишем полученое в файл test
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second><![CDATA[<second>]]></second>
    <!--it's a comment-->
    <second><![CDATA[some string]]></second>
    <third>TEST</third>
    <third>some string</third>
    <third>some string</third>
    <third><![CDATA[<second>]]</third>
    <line><![CDATA[<second>]]></line>
</first>

десереализуем xml обратно в обьект
FirstSecondObject{seconds=[<second>, some string], thirds=[TEST, some string, some string, <![CDATA[<second>]]], line='<second>'}

сереализуем этот объект в xml
toXmlWithComment(obj, "second", "it's a comment")

пищем в файл test2
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second><![CDATA[<second>]]></second>
    <!--it's a comment-->
    <second><![CDATA[some string]]></second>
    <third>TEST</third>
    <third>some string</third>
    <third>some string</third>
    <third><![CDATA[<second>]]</third>
    <line><![CDATA[<second>]]></line>
</first>

взвешиваем файлы
System.out.format("F1size=%d F2size=%d \n",
                    Files.size(Paths.get("/home/user/temp/test")), Files.size(Paths.get("/home/user/temp/test2"))
            );

результат
F1size=413 F2size=413 

Что не так? :C
serod1306
а если будет
<second/>
коммент напишет,
iZulrad
  • iZulrad
  • 0
  • Комментарий отредактирован 2015-01-23 17:26:26 пользователем iZulrad
Да.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second><![CDATA[<second>]]></second>
    <!--it's a comment-->
    <second><![CDATA[some string]]></second>
    <!--it's a comment-->
    <second value="Third string"/>
    <line><![CDATA[<second>]]></line>
</first>
и так
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second><![CDATA[<second>]]></second>
    <!--it's a comment-->
    <second><![CDATA[some string]]></second>
    <!--it's a comment-->
    <second/>
    <line><![CDATA[<second>]]></line>
</first>
Diana
да, пропущен
Diana
Пример класса для тестирования:

    @XmlType(name = "anExample")
    @XmlRootElement
    public static class AnExample {
        public String[] needCDATA = new String[]{"need CDATA because of < and >", ""};
    }



Пример вызова:

String result = Solution.toXmlWithComment(new AnExample(), "needCDATA", "it's a comment - <needCDATA>");


Ожидаемый результат:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<anExample>
    <!--it's a comment - <needCDATA>-->
    <needCDATA><![CDATA[need CDATA because of < and >]]></needCDATA>
    <!--it's a comment - <needCDATA>-->
    <needCDATA/>
</anExample>

iZulrad
  • iZulrad
  • 0
  • Комментарий отредактирован 2015-02-04 21:37:22 пользователем iZulrad
это
@XmlType(name = "anExample")
    @XmlRootElement
    public static class AnExample {
        public String[] needCDATA = new String[]{
                "need CDATA because of < and >", "",
                "Не оборачиваем", "!< а вот это обернем"};

        public String[][] data = new String[][]{
                new String[]{" < ДА! ", " nonono "},
                new String[]{" YEP & ", "DONNO!"},
                new String[]{" неа  ", "нет нетЕНЕТЕТЕТЕ!"},
                new String[]{" need CDATA because of < and >  ", "и снова нет"}
        };
    }

так
String s = com.javarush.test.level33.lesson10.bonus01.Solution.toXmlWithComment(
                new AnExample(), "needCDATA", "it's a comment - <needCDATA>");
        System.out.println(s);

вот в это
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<anExample>
    <!--it's a comment - <needCDATA>-->
    <needCDATA><![CDATA[need CDATA because of < and >]]></needCDATA>
    <!--it's a comment - <needCDATA>-->
    <needCDATA/>
    <!--it's a comment - <needCDATA>-->
    <needCDATA>Не оборачиваем</needCDATA>
    <!--it's a comment - <needCDATA>-->
    <needCDATA><![CDATA[!< а вот это обернем]]></needCDATA>
    <data>
        <item><![CDATA[ < ДА! ]]></item>
        <item> nonono </item>
    </data>
    <data>
        <item><![CDATA[ YEP & ]]></item>
        <item>DONNO!</item>
    </data>
    <data>
        <item> неа  </item>
        <item>нет нетЕНЕТЕТЕТЕ!</item>
    </data>
    <data>
        <item><![CDATA[ need CDATA because of < and >  ]]></item>
        <item>и снова нет</item>
    </data>
</anExample>
iZulrad
А @XmlRootElement может быть @XmlRootElement(name=«needCDATA»), если да ему нужно писать камент?
vps
  • vps
  • 0
  • Комментарий отредактирован 2015-02-26 17:57:38 пользователем vps
Diana, точно ли надо вставлять комментарий в первом случае предложенного Вами ожидаемого результата?
Вроде в задании написано:
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.

П.С.: чего-то я запутался. Надо бы больше примеров.
Sdu
На сколько я понял, имеется в виду, что непосредственно внутрь CDATA не нужно вставлять комментарий, если там есть строка эквивалентная искомому тэгу.

<second><![CDATA[need CDATA comment because of < and > signs. Don't need before that <second> placed inside CDATA]]></second>


Обрати внимание на кусок:
Don't need before that placed inside CDATA
vps
  • vps
  • 0
  • Комментарий отредактирован 2015-02-27 10:50:49 пользователем vps
Т.е. если я правильно понял, то вот с таким классом и примером запуска:
<code>
@XmlType(name = "anExample")
@XmlRootElement(name = "first")
public static class anExample 
{
   public String[] second = new String[]{"need CDATA comment because of < and > signs. Don't need before that <second> placed inside CDATA", ""};
   public String third = "<second>";
}
/////
String result = Solution.toXmlWithComment(new anExample(), "second", "it's a comment - <needCDATA>");
</code>

Я должен получить вот такое?
<code><?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
   <!--it's a comment - <needCDATA>-->
   <second><![CDATA[need CDATA comment because of < and > signs. Don't need before that <second> placed inside CDATA]]></second>
   <!--it's a comment - <needCDATA>-->
   <second/>
   <third><![CDATA[<second>]]></third>
</first></code>
Sdu
Судя по всему, да.
vps
  • vps
  • 0
  • Комментарий отредактирован 2015-02-27 11:01:40 пользователем vps
Программа не проходит тестирование!

П.С.: не получается сдать это задание с ноября прошлого года. Не помешали бы правильные примеры…
Sdu
Добро пожаловать в клуб =)
Судя по всему, есть какая-то хитрость с CDATA. В чем она заключается, я лично понять не могу.
vps
  • vps
  • 0
  • Комментарий отредактирован 2015-02-27 11:10:06 пользователем vps
Судя по статистике, кто-то понял с 265 попыток! :)
Sdu
Жаль не я ) Вчера еще никого не было…
vps
  • vps
  • 0
  • Комментарий отредактирован 2015-03-02 12:44:40 пользователем vps
Подниму тему…

П.С.: если в параметрах вызываемого метода передавать null, то что возвращать (пустую строку и null)?
Sdu
Diana ниже в ветке ответила что таких тестов нет.
vps
Тогда ждём ответов о том, что ещё надо учитывать от тех, кто сдал задачу. :)
isc
  • isc
  • +1
  • Комментарий отредактирован 2015-04-15 06:06:02 пользователем isc
Используя ваш пример класса для тестирования, получаю
<code><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<anExample>
    <needCDATA>need CDATA because of < and ></needCDATA>
    <needCDATA></needCDATA>
</anExample></code>

Какими волшебными словами вы заставляете маршаллер генерировать тег CDATA и автозакрывающийся тег?
B0gdan
Получаю на выходе
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<anExample>
    <!--it's a comment - <needCDATA>-->
	<needCDATA>need CDATA because of < and ></needCDATA>
    <!--it's a comment - <needCDATA>-->
	<needCDATA></needCDATA>
</anExample>

В какой-то мере близко к истине. Очень хотелось бы увидеть волшебные слова которые приводят хмл в порядок (например заменяют обычные теги автозакрывающимиися там, где это возможно). Или надо это всё писать вручную?
iZulrad

    @XmlType(name = "anExample")
    @XmlRootElement(name = "needCDATA")
    public static class AnExample {
        @XmlElement(name = "needCDATA")
        public String needCDATA3 = "";

        public String[][] needCDATA = new String[][]{
                new String[]{" < ДА! ", " nonono "},
                new String[]{" need CDATA because of < and >  ", "и снова нет"}
        };

        public AnExample2 anExample2 = new AnExample2();

    }

    @XmlType(name = "anExample2")
    public static class AnExample2 {
        public AnExample3 anExample3 = new AnExample3();
        @XmlElement(name = "needCDATA")
        public String needCDATA = "<needCDATA>";
        @XmlElement(name = "needCDATA")
        public String needCDATA2 = "НЕТ";
        @XmlElement(name = "needCDATA")
        public String needCDATA3 = "";

    }

    @XmlType(name = "anExample3")
    public static class AnExample3 {
        @XmlElement(name = "needCDATA")
        public String needCDATA = "<needCDATA>";
    }

результат
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<needCDATA>
    <!--it's a comment - <needCDATA>-->
    <needCDATA/>
    <!--it's a comment - <needCDATA>-->
    <needCDATA>
        <item><![CDATA[ < ДА! ]]></item>
        <item> nonono </item>
    </needCDATA>
    <!--it's a comment - <needCDATA>-->
    <needCDATA>
        <item><![CDATA[ need CDATA because of < and >  ]]></item>
        <item>и снова нет</item>
    </needCDATA>
    <anExample2>
        <anExample3>
            <!--it's a comment - <needCDATA>-->
            <needCDATA><![CDATA[<needCDATA>]]></needCDATA>
        </anExample3>
        <!--it's a comment - <needCDATA>-->
        <needCDATA><![CDATA[<needCDATA>]]></needCDATA>
        <!--it's a comment - <needCDATA>-->
        <needCDATA>НЕТ</needCDATA>
        <!--it's a comment - <needCDATA>-->
        <needCDATA/>
    </anExample2>
</needCDATA>
kolust
  • kolust
  • 0
  • Комментарий отредактирован 2015-03-03 17:31:28 пользователем kolust
а не нужен ли коммент перед самым первым
<needCDATA>
(вторая строка)???
vps
Я думаю, что нужен. По крайней мере, у меня так реализовано.

П.С.: задачу пока не сдал! :)
Sdu
  • Sdu
  • +1
Diana , а как быть с CDATA в неинтересующих нас тэгах?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<anExample>
    <!--it's a comment - <needCDATA>-->
    <needCDATA><![CDATA[need CDATA because of < and >]]></needCDATA>
    <!--it's a comment - <needCDATA>-->
    <needCDATA/>
    <other>need CDATA because of < and ></other>
    <other/>
</anExample>


Если это влияет на прохождение тестов, то получается что нужно проходить по всему дереву XML и проверять нужен ли CDATA, а не выбирать только тэги с именем tagName?

Влияет ли форматирование получившегося документа на прохождение теста? Имеется в виду количество отступов, ил и к примеру вот такое расположение комментария:
<!--it's a comment - <needCDATA>--><anExample>
Diana
CDATA нужна везде
форматирование результата не влияет на тесты
Sdu
Есть ли в тестах варианты когда tagName и/или comment равно null?
Какой результат ожидается в этом случае? Пустая строка? Или сериализованный объект без комментариев? Или комментарии к каждому тегу (если tagName = null)?
Diana
нет
okolorevanchik
Комментарии должны вставляться перед тегами, содержащими префиксы? При условии, что в метод приходит только имя тега.
okolorevanchik
И еще, должны ли обрамляться СDATA'ой значения тегов, содержащие " и '? Или они должны обрамляться только в том случае, если изначально отображаются как спецсимволы?
Sdu
Есть четкий перечень символов, которые должны экранироваться тэгом CDATA, ищите в доках.
Olegator3
Помогите, достала уже задача эта >.<
Вот мое решение, не очень красивое но все тесты выше прошли как по маслу…

public class Solution {
    public static void main(String[] args)
    {
        System.out.println(toXmlWithComment(new Cat("Яша", 14, 16), "name", "test"));
    }
    public static String toXmlWithComment(Object obj, String tagName, String comment) {
      
        try
        {
            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            StringWriter writer = new StringWriter();

            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            marshaller.marshal(obj, writer);

            String xml = writer.toString();
            String commentPut = "<!--"+comment+"-->";
            String tag = "<"+tagName;

            //Создаю регулярку для поиска CDATA
            Pattern pattern = Pattern.compile("(<!\\[CDATA\\[(.|\n)*?]]>)");
            Matcher matcher = pattern.matcher(xml);
            //Все найденные CDATA кладу в лист
            List<String> cdatas = new ArrayList<>();
            while (matcher.find()){
                cdatas.add(matcher.group());
            }
            //Заменяю все CDATA на другой тег
            xml = (xml.replaceAll(pattern.pattern(),"<URURU/>"));

            //ставлю комментарии в xml в котором нету CDATA и есть URURU teg
            List<String> list = new ArrayList<>(Arrays.asList(xml.split("\n")));
            List<String> copy = new ArrayList<>(list);
            for(int i =0;i<copy.size();i++){
                String s = copy.get(i);
                if(s.contains(tag)){
                    int count = spaceCount(s);
                    for(int j =0;j<count;j++){
                       commentPut = " "+commentPut;
                    }
                    list.set(i,commentPut+"\n"+s);
                    commentPut = commentPut.trim();
                }

            }
            //делаю новый xml который уже с комментами
            StringBuilder comments = new StringBuilder();
            for(String elem : list){
                comments.append(elem+"\n");
            }
            xml = comments.toString();


            //заменяю все URURU обратно на CDATA
             List<String> ururu = new ArrayList<>(Arrays.asList(xml.split("<URURU/>")));
            for(int i =0;i<cdatas.size();i++){
                String s = ururu.get(i);
                s+=cdatas.get(i);
                ururu.set(i,s);
            }

            //Делаю финальный xml
            StringBuilder result = new StringBuilder();
            for(String cdata : ururu)
            result.append(cdata);


        return result.toString().replace("standalone=\"yes\"","standalone=\"no\"");

        }
        catch (JAXBException e)
        {
            e.printStackTrace();
            return "";
        }
    }
    //штука для счета пробелов
    public static int spaceCount(String word){
        word = word.substring(0,word.indexOf("<"));
        int count = 0;
        char[] array = word.toCharArray();
        for(Character charc : array){
            if(charc == ' ')count++;
        }
        return count;
    }
}
nicolas
После недавнего обновления тестов принялось решение. Просьба админам убрать код.
chekist
И правда рабочий, печаль…
vital_63_
  • vital_63_
  • 0
  • Комментарий отредактирован 2016-05-06 16:29:32 пользователем vital_63_
Честно говоря, делал по образу и подобию этого примера. Не то чтобы передрал тупо, явного копирования (CTRL + C) вообще не делал. Но все равно получилось очень похоже. Образец достойный. Только метод replaceTextWithCDATA сделал нерекурсивным. Туда же все теги приходят до единого, вложенные не пропускаем. Для каждого перебирал вложенные ноды (первого уровня только) и для них уже проверял условие, что это текст и что содержит спецсимволы. Только одного не понял:
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", «4»);
что это за строка такая "{http://xml.apache.org/xslt}indent-amount". И почему она дает такой эффект? Причем от неё ни убавить, ни прибавить ничего нельзя. Хоть один символ в ней поменять: эффект форматирования отступами пропадает. Констант я таких не нашел нигде, в документации тоже про такую строку ничего нет. Откуда она взялась и почему так работает?
Кстати: у меня файл моега класса лежал в этом же пакете с Solution, из-за этого была ошибка компиляции.
remain4life
Только одного не понял:
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", «4»);
что это за строка такая "{http://xml.apache.org/xslt}indent-amount"
— гораздо понятнее использовать установку отступов через TransformerFactory, тут всё прозрачно:
TransformerFactory tf = TransformerFactory.newInstance();
            tf.setAttribute("indent-number", 4);
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes")
olegvasylkov
долго пытался сделать самостоятельно, но постоянно был за пол шага до решения, пока не нашел этот комент. спасибо
isc
  • isc
  • 0
  • Комментарий отредактирован 2015-04-15 08:52:31 пользователем isc
Использовал код из этой статьи.
Мои тесты проходит.
что делаю не так?


package com.javarush.test.level33.lesson10.bonus01;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.io.Writer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;


/* Комментарий внутри xml
Реализовать метод toXmlWithComment, который должен возвращать строку - xml представление объекта obj.
В строке перед каждым тэгом tagName должен быть вставлен комментарий comment.
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.

Пример вызова:  toXmlWithComment(firstSecondObject, "second", "it's a comment")
Пример результата:
<?xml version="1.0" encoding="UTF-8" standalone="no">
<first>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
</first>
*/
public class Solution
{
    public static String toXmlWithComment(Object obj, String tagName, String comment) throws Exception
    {
        StringWriter writer = new StringWriter();
        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(obj, writer);
        String out = writer.toString().split("\n")[0] + "\n";
        writer = new StringWriter();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
        marshaller.marshal(obj, writer);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(writer.toString().getBytes());
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setValidating(false);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(byteArrayInputStream);
        Element element = doc.getDocumentElement();
        Comment com = null;
        NodeList elements = element.getElementsByTagName(tagName);
        for (int i = 0; i < elements.getLength(); i++)
        {
            com = doc.createComment(comment);
            element.insertBefore(com, elements.item(i));
        }

        Transformer tf = TransformerFactory.newInstance().newTransformer();
        tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        tf.setOutputProperty(OutputKeys.INDENT, "yes");
        tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        Writer sw = new StringWriter();
        tf.transform(new DOMSource(doc), new StreamResult(sw));
        out += sw.toString();
        return out;
    }

    
}

isc
  • isc
  • 0
  • Комментарий отредактирован 2015-04-15 09:12:53 пользователем isc
ссылка на статью не прицепилась к исходному сообщению
examples.javacodegeeks.com/core-java/xml/dom/add-comment-to-dom-document/
Fry
  • Fry
  • 0
  • Комментарий отредактирован 2015-04-18 18:43:28 пользователем Fry
Вопрос к решившим. Какая версия XML используется в тестах XML 1.0, или другая? А также какие спец символы нужно оборачивать в СДАТА?
1)
< <
> >
& &
' '
" "

2) Спецсимволы XML
Код Обозначение Описание
#x9 [HT] Горизонтальная табуляция (horizontal tabulation)
#xA [LF] Перевод строки (line feed)
#xD [CR] Возврат каретки (carriage return)
#x20 [SP] Пробел (space)
#x21! Восклицательный знак (exclamation sign)
#x22 " Двойные кавычки (quotation mark)
#x26 & Амперсант (ampersand)
#x27 ' Апостроф или одинарные кавычки (apostrophe)
#x3C < «Знак „“меньше»" или левая угловая скобка (less-than sign)"
#x3F? Вопросительный знак (question mark)
#xA0 [NBSP] Неразрываемый пробел (no-break space)

3)

4) или эти записанны в регулярке String xml10pattern = "[^" + "\u0009\r\n" + "\u0020-\uD7FF" + "\uE000-\uFFFD" + "\ud800\udc00-\udbff\udfff" + "]";

В своем решении я делал через w3c.dom, но думаю проблема именно в нем, собирает XML он по другому чем нужно тестам. Хотелось бы узнать каким парсером решили задачу? Или в ручную, в стринге ковырятся?
taras19921
Добрий день всім! Я так розумію, що треба зробити маршалінг об'єкта,
JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(obj, writer);

але Не розумію, як вставити коментарі перед кожним тегом.
alexwow
вот рабочий код, в котором использовал парсинг XML, а не текста
где те 6%, которые решили это задание?

    public static String toXmlWithComment(Object obj, String tagName, String comment)
    {
        StringWriter stringWriter = new StringWriter();
        try
        {
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            marshaller.marshal(obj, stringWriter);
        } catch (JAXBException ignore) {/*NOP*/}

        try
        {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            docFactory.setValidating(false);
            DocumentBuilder documentBuilder = docFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(new ByteArrayInputStream(stringWriter.toString().getBytes("UTF-8")));
            document.normalize();

            Comment commentXml;

            NodeList nodeList = document.getElementsByTagName(tagName);
            for(int i = 0; i < nodeList.getLength(); i++)
            {
                commentXml = document.createComment(comment);
                nodeList.item(i).getParentNode().insertBefore(commentXml, nodeList.item(i));

            }

            find(document, document);

            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
            DOMSource domSource = new DOMSource(document);

            StringWriter resultString = new StringWriter();
            StreamResult result = new StreamResult(resultString);
            transformer.transform(domSource,result);

            stringWriter = resultString;

        } catch (Exception e){
            e.printStackTrace();
        }

        return stringWriter.toString();
    }

    public static void find(Node node, Document dc){

        for(Node i = node.getFirstChild(); i != null; i = i.getNextSibling()){
            if(!i.hasChildNodes()){
                process(i, dc);
            } else {
                find(i, dc);
            }
        }
    }

    public static void process(Node node, Document dc){
        if(node.getNodeType() == Node.TEXT_NODE)
        {
            String text = node.getTextContent();
            if (text != null && !text.equals("") && text.matches("(.*)[<>&](.*)"))
            {
                Element parent = (Element) node.getParentNode();
                parent.setTextContent("");
                parent.appendChild(dc.createCDATASection(text));
            }
        }
    }
maxim343
  • maxim343
  • 0
  • Комментарий отредактирован 2015-05-25 19:16:28 пользователем maxim343
Моё решение не принимается, пишет: ошибка компиляции, хотя никаких сторонних библиотек я не использовал, только jdk.
maxim343
  • maxim343
  • 0
  • Комментарий отредактирован 2015-05-25 19:56:20 пользователем maxim343
com.sun.xml.internal.bind.marshaller.*
javax.*
org.w3c.dom.*

что-то из этого запрещено?
kiruxam
замени
com.sun.xml.internal.bind.marshaller.*

на
javax.xml.bind.Marshaller;
maxim343
  • maxim343
  • 0
  • Комментарий отредактирован 2015-05-31 13:42:00 пользователем maxim343
Спасибо kiruxam . Но я переписал логику работы метода без использования этого пакета. Но всё равно не принимается
Diana
на днях Зепп зальет изменения, которые включают обновления тестов этой задачи
sergeevii
Пожалуйста отпишите здесь, когда будут изменения в тестах)
dimitor
тогда заодно включите и пару сложных примеров в текст задания…
Alex1992
Решил эту задачу, потратил 2 дня и 2 ночи всего лишь)
Я решал так: Маршалинг объекта(сериализация с помощью JAXB) в Document(Фреймворк: org.w3c.dom.*), затем уже дело техники, нужно обернуть с помощью инструментов DOM все текстовые поля которые содержат escape — последовательности(Задания принялось только тогда, когда в шаблоне были прописаны все метасимволы которые давались в лекциях (не больше не меньше)) в CDATA. Также у меня был один приватный рекурсивный метод на тесты это не повлияло
Docktor91
помогайте друзья)
package com.javarush.test.level33.lesson10.bonus01;


import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringReader;
import java.io.StringWriter;

/* Комментарий внутри xml
Реализовать метод toXmlWithComment, который должен возвращать строку - xml представление объекта obj.
В строке перед каждым тэгом tagName должен быть вставлен комментарий comment.
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.

Пример вызова:  toXmlWithComment(firstSecondObject, "second", "it's a comment")
Пример результата:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second><![CDATA[need CDATA because of < and >]]></second>
    <!--it's a comment-->
    <second/>
</first>
*/
public class Solution
{
    public static String toXmlWithComment(Object obj, String tagName, String comment) throws Exception
    {
        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();

        StringWriter stringWriter = new StringWriter();
        marshaller.marshal(obj, stringWriter);
        stringWriter.close();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(new InputSource(new StringReader(stringWriter.toString())));
        document.setXmlStandalone(false);

        changeTextNodesToCdataNodes(document, document);
        NodeList list = document.getElementsByTagName(tagName);

        for (int i = 0; i < list.getLength(); i++)
            list.item(i).getParentNode().insertBefore(document.createComment(comment), list.item(i));

        Transformer transformer = TransformerFactory.newInstance()
                .newTransformer();
        stringWriter = new StringWriter();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StreamResult result = new StreamResult(stringWriter);

        transformer.transform(source, result);
        stringWriter.close();
        return stringWriter.toString();
    }

    private static void changeTextNodesToCdataNodes(Node firstNode, Document ownerDocument)
    {

        if (firstNode.hasChildNodes())
        {
            NodeList children = firstNode.getChildNodes();

            for (int i = 0; i < children.getLength(); i++)
            {
                Node node = children.item(i);
                if (node.getNodeType() == Node.TEXT_NODE)
                {
                    if (node.getTextContent().matches(".*[<>&]"))
                        node.getParentNode().replaceChild(ownerDocument.createCDATASection(node.getTextContent()), node);
                } else
                {
                    changeTextNodesToCdataNodes(node, ownerDocument);
                }
            }
        }
        return;
    }
}
Docktor91
regexp поправлен на
.*[<>&].*
Docktor91
всем спасибо, задача решена
svorobei
я не пойму. а разве не должна вылетать ошибка при парсинге, если внутри тега есть те самые .*[<>&].* последовательности?? у меня вылазиет ексепшен(
Docktor91
если при сериализации в каком нибудь поле объекта есть символы
<>&'"
(это все) то нужно это учесть и заменить в хмлке на секции СДАТА
svorobei
заменить в хмлке на секции СДАТА
для этого нужно в JAXB'е какой-то параметр задать? или средствами парсера? (createCDATASection)
Docktor91
смотри мой код выше)
svorobei
не принимает твой код)
svorobei
Народ, посмотрите, пж-ста, кто решал через регулярки (если есть такие вообще).
работает, но не принимает. может есть у кого идеи?)

package com.javarush.test.level33.lesson10.bonus01;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/* Комментарий внутри xml
Реализовать метод toXmlWithComment, который должен возвращать строку - xml представление объекта obj.
В строке перед каждым тэгом tagName должен быть вставлен комментарий comment.
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.

Пример вызова:  toXmlWithComment(firstSecondObject, "second", "it's a comment")
Пример результата:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second>some string</second>
    <!--it's a comment-->
    <second><![CDATA[need CDATA because of < and >]]></second>
    <!--it's a comment-->
    <second/>
</first>
*/
public class Solution {
    public static String toXmlWithComment(Object obj, String tagName, String comment) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        StringWriter writer = new StringWriter();
        marshaller.marshal(obj, writer);

        String string = writer.toString();
        //находим позиции всех тегов tagName
        Pattern pattern = Pattern.compile("<"+tagName);
        Matcher matcher = pattern.matcher(string);


        ArrayList<Integer> positions = new ArrayList<>();

        while (matcher.find()){
            //добавляем их в список
            positions.add(matcher.start());
        }
        //находит все теги cdata
        Pattern pattern2 = Pattern.compile("<!\\[CDATA\\[.*?\\]\\]>");
        Matcher matcher2 = pattern2.matcher(string);
        //и проверяем есть ли теги tagName внутри найденных cdata
        //если да, то убираем из списка
        while (matcher2.find()) {
            int start = matcher2.start();
            int end = start + matcher2.group().length();

            for (int i = 0; i < positions.size(); ) {

                if (positions.get(i)>start && positions.get(i)<end) {
                    positions.remove(i);
                }
                else i++;
            }
        }
        //вставляем комменты перед тегами
        StringBuilder sb = new StringBuilder(string);
        for (int i = positions.size()-1; i >=0; i--) {
            sb.insert(positions.get(i), "<!--"+comment+"-->\n");
        }

        return sb.toString();
    }

/////////////////////////////////// ДЛЯ ТЕСТА
      public static void main(String[] args) throws JAXBException {
        String string = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
                "<first>\n" +
                "<second>some string</second>\n" +
                "<second>some string</second>\n" +
                "<second><![CDATA[" +
                "need CDATA because of <second>some string</second>" +
                "<second>some string</second>]]></second>\n" +
                "<second/>\n" +
                "</first>";

        System.out.println(string);
        System.out.println();
        Pattern pattern = Pattern.compile("<second");
        Matcher matcher = pattern.matcher(string);


        ArrayList<Integer> positions = new ArrayList<>();

        while (matcher.find()){
        positions.add(matcher.start());
        }

          Pattern pattern2 = Pattern.compile("<!\\[CDATA\\[.*?\\]\\]>");
          Matcher matcher2 = pattern2.matcher(string);

          while (matcher2.find()) {
              int start = matcher2.start();
              int end = start + matcher2.group().length();

              for (int i = 0; i < positions.size(); ) {

                  if (positions.get(i)>start && positions.get(i)<end) {
                      positions.remove(i);
                  }
                  else i++;
              }
          }
        StringBuilder sb = new StringBuilder(string);

        for (int i = positions.size()-1; i >=0; i--) {
            sb.insert(positions.get(i), "<!--it's a comment-->\n");
        }

        System.out.println(sb.toString());
    }
}
olegvasylkov
Использовал пример Diana , работает корректно, но не проходит. Где может быть проблема?
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

import org.w3c.dom.*;

public class Solution {

    public static void main(String[] args) throws Exception
    {
        String result = toXmlWithComment(new AnExample(), "needCDATA", "it's a comment - <needCDATA>");
        System.out.println(result);
    }


    @XmlType(name = "anExample")
    @XmlRootElement
    public static class AnExample {
        public String[] needCDATA = new String[]{"need CDATA because of < and >", ""};
    }

    public static String toXmlWithComment(Object obj, String tagName, String comment) throws Exception
    {
        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

        JAXBContext context = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.marshal(obj, doc);

        NodeList nodeList = doc.getElementsByTagName("*");
        for (int i = 0; i < nodeList.getLength(); i++){
            Node node = nodeList.item(i);
            if (node.getNodeName().equals(tagName))
            {
                node.getParentNode().insertBefore(doc.createComment(comment), node);
            }
        }

        Transformer tf = TransformerFactory.newInstance().newTransformer();
        tf.setOutputProperty(OutputKeys.INDENT, "yes");
        doc.getAttributes();
        for (int i = 0; i < nodeList.getLength(); i++){
            String tag = nodeList.item(i).getNodeName();
            tf.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, tag);
        }
        tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

        StringWriter out = new StringWriter();
        tf.transform(new DOMSource(doc), new StreamResult(out));
        return out.toString();
    }
}
NataliaIlchenko
У меня одной такое впечатление от задачи?

Вроде, худо-бедно дошла сама почти до конца 33 уровня и тут БАЦ: люди пишут в кодах TransformerFactory, OutputKeys.CDATA_SECTION_ELEMENTS, doc.getElementsByTagName… А где это проходилось вообще?
Либо народ это откуда-то передирает, либо к 33 уровню у всех развилась мистическая телепатия, потому как с бухты-барахты такого не придумаешь и с потолка не возьмешь.

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

Спасибо за внимание.
remain4life
Ну к 33 уровню идея курса уже должна быть понятна — задачи часто даются на непройденный материал, чтобы человек сам поковырялся в гугле, а не только в лекциях :) Кроме того, задача помечена как повышенной сложности. У меня осмысление и решение задачи вместе с чтением материала заняло почти 3 дня. На самом деле, не всё так сложно, возможные пути решения:
1) сделать сериализацию в String и там долго и муторно ковыряться с тэгами, используя уже пройденный материал,
2) либо погуглить о стандартном фреймворке JDK org.w3c.dom.* и DOM — и решить задачу намного проще с использованием уже предназначенных для этого методов.
Я выбрал второй способ — и мне большей частью хватило материалов из стандарных оракловских мануалов + несколько примеров на stackoverflow.com/
Вот перечень ссылок, по которым я ходил в процессе решения задачи:
Легче всего начать с этого:
www.quizful.net/post/getting-started-with-xml-in-java
ru.wikipedia.org/wiki/Document_Object_Model
Document/Node:
stackoverflow.com/questions/17078308/how-to-marshal-a-jaxb-object-to-org-w3c-dom-document
docs.oracle.com/javase/7/docs/api/org/w3c/dom/Document.html
docs.oracle.com/javase/7/docs/api/org/w3c/dom/Node.html
docs.oracle.com/javase/7/docs/api/org/w3c/dom/NodeList.html
docs.oracle.com/javase/7/docs/api/constant-values.html
stackoverflow.com/questions/6869384/add-comment-programatically-to-xml
Вывод из Document:
docs.oracle.com/javase/7/docs/api/javax/xml/transform/Transformer.html
docs.oracle.com/javase/7/docs/api/javax/xml/transform/TransformerFactory.html
stackoverflow.com/questions/1384802/java-how-to-indent-xml-generated-by-transformer
stackoverflow.com/questions/277996/jaxb-remove-standalone-yes-from-generated-xml
docs.oracle.com/javase/7/docs/api/javax/xml/transform/OutputKeys.html
Удачи в решении :)
mo3gach
  • mo3gach
  • 0
  • Комментарий отредактирован 2016-12-27 20:21:11 пользователем mo3gach
Подскажите, кто решал через Dom — почему не проходит? Вывод вроде совпадает:
public static String toXmlWithComment(Object obj, String tagName, String comment) {
        String result = null;
        StringWriter writer = new StringWriter();
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document document = db.newDocument();

            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            Marshaller marshaller = context.createMarshaller();

            marshaller.marshal(obj, document);

            NodeList elements = document.getElementsByTagName(tagName);
            for(int i=0; i<elements.getLength(); i++) {
                Node element = elements.item(i);
                element.getParentNode().insertBefore(document.createComment(comment), element);
            }

            TransformerFactory tf = TransformerFactory.newInstance();
            tf.setAttribute("indent-number", 4);
            Transformer t = tf.newTransformer();
            t.setOutputProperty(OutputKeys.INDENT, "yes");
            t.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, tagName);
            t.transform(new DOMSource(document), new StreamResult(writer));
            result = writer.toString();
        } catch (Exception e) {

        }
        return result;
mo3gach
проблему нашел, здесь случайно везде была cdata, а я и не заметил :)
angelrum
Целые сутки провел за задачей и все-таки ее решил.
Следующим проходцам хотел оставить подсказки:
1. При сериализации проверяйте записанный текст (значения) в тегах, если есть специальные символы xml, то содержимое оборачивайте в CDATA;
<second>need CDATA because of < and ></second>

превращается в
<second><![CDATA[need CDATA because of < and >]]></second>

2. Сравнивайте возвращаемый результат метода с результатом сериализации (после того, как создается экземпляр DOMSource из Document, некоторые данные из заголовка могут «пропасть»);
3. Нельзя создать один экземпляр Node с комментарием и добавить его во все нужные места документа, запишется только последний, перед каждым добавлением создаем уникальный комментарий;
4. И в Transformer необходимо присвоить загадочное св-во OutputKeys.CDATA_SECTION_ELEMENTS, визуально ни как не повлияло на xml, но его отсутствие валидатору не нравиться.
Задача на 5+, хорошо прокачивает скил. Еще рекомендую пройтись по ссылкам которые выложил remain4life.
Всем удачи и огромного терпения :)
angelrum
  • angelrum
  • 0
  • Комментарий отредактирован 2017-03-19 00:52:55 пользователем angelrum
п.4 это св-во оборачивает значения в указанном теге в CDATA.
anomi
товарищи, сделал метод, прочитав всю ветку переписок тут. Но валидатор не принимает все равно. Помогите пожалуйста

public static String toXmlWithComment(Object obj, String tagName, String comment) throws IOException {
        String stringOut = null;
        StringWriter writer = new StringWriter();
        try {
            //создаем дерево, состоящее из тэгов
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.newDocument();
            document.setXmlStandalone(false);

            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            //делаем маршалинг в объект document
            marshaller.marshal(obj, document);

            //делаем CDATA, если нужно
            changeTextToCDATA(document, document);

            //добавляем комменты
            NodeList nodeList = document.getElementsByTagName(tagName);
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node element = nodeList.item(i);
                element.getParentNode().insertBefore(document.createComment(comment), element);
            }


            /**
             * DOMSource(document) - источник xml - дерева
             * new StreamResult(writer) - поток, который запишет xml-дерево во writer
             */
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(new DOMSource(document), new StreamResult(writer));

            stringOut = writer.toString();
        }
        catch (Exception e){}
        finally {
            writer.close();
        }

        return stringOut;
    }

    private static void changeTextToCDATA(Node mainNode, Document document){
        if (mainNode.hasChildNodes()){
            NodeList children = mainNode.getChildNodes();
            for (int i = 0; i < children.getLength(); i++) {
                Node node = children.item(i);
                if (node.getNodeType() == Node.TEXT_NODE){
                    if (node.getTextContent().matches(".*[<>&].*")) {

                        Node newNode = document.createCDATASection(node.getTextContent());
                        node.getParentNode().replaceChild(newNode, node);
                    }
                }
                else
                    changeTextToCDATA(node, document);
            }
        }
    }

    @XmlType(name = "first")
    @XmlRootElement
    public static class First {
        public String[] second = new String[]{
                "some string",
                "some string",
                "need CDATA because <second> of < and >",
                ""};
    }
Artem_Novikov
  • Artem_Novikov
  • 0
  • Комментарий отредактирован 2017-08-15 11:16:16 пользователем Artem_Novikov
Задача из разряда «подгони решение под опыт предков».
И на мой взгляд итоговое решение не соответствует условию.
realcorwin
Это задача из разряда «Авторы поленились писать лекцию» :).
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.